home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #11 / Amiga Plus CD - 2004 - No. 11.iso / AmiSoft / Game / misc / WormWars.lha / WormWars / Source / engine1.c < prev    next >
C/C++ Source or Header  |  2004-08-22  |  93KB  |  2,785 lines

  1. // 1. INCLUDES -----------------------------------------------------------
  2.  
  3. #include <string.h>
  4. #include <math.h>
  5. #include <stdio.h>
  6. #include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */
  7.  
  8. #include "stdafx.h"
  9. #include "diff.h"
  10. #include "same.h"
  11. #include "engine.h"
  12.  
  13. /* Rules for variable types:
  14.  
  15. SBYTE is used for field coordinates and queue indices
  16. UBYTE is used for contents
  17. SWORD is used for frequencies
  18. ULONG is used for scores */
  19.  
  20. // 2. DEFINES ------------------------------------------------------------
  21.  
  22. // 3. EXPORTED VARIABLES -------------------------------------------------
  23.  
  24. ABOOL anims      = TRUE,
  25.       banging    = FALSE,
  26.       clearthem  = FALSE,
  27.       enclosed   = FALSE,
  28.       engraved   = TRUE,
  29.       modified   = FALSE,
  30.       randomflag = FALSE,
  31.       randomarray[MAXLEVELS + 1],
  32.       turbo      = FALSE;
  33. UBYTE board[MAXLEVELS + 1][MINFIELDX + 1][MINFIELDY + 1],
  34.       engraving,
  35.       field[MAXFIELDX + 1][MAXFIELDY + 1],
  36.       tailfield[MAXFIELDX + 1][MAXFIELDY + 1],
  37.       ice;
  38. SBYTE a = GAMEOVER,
  39.       players,
  40.       level = 1, levels, reallevel, sourcelevel,
  41.       numberx, numbery, number,
  42.       treasurer,
  43.       startx[MAXLEVELS + 1], starty[MAXLEVELS + 1];
  44. SWORD fieldx, fieldy,
  45.       secondsleft, secondsperlevel;
  46. TEXT  pathname[81],
  47.       date[DATELENGTH + 1],
  48.       times[TIMELENGTH + 1],
  49.       stattext[7 + 1];
  50. ULONG delay, r;
  51. ULONG quantity[5][3];
  52.  
  53. AGLOBAL struct HiScoreStruct   hiscore[HISCORES + 1];
  54. AGLOBAL struct WormStruct      worm[4];
  55. AGLOBAL struct TeleportStruct  teleport[2];
  56. AGLOBAL struct ProtectorStruct protector[4][PROTECTORS + 1];
  57. AGLOBAL struct MagnetStruct    magnet[MAGNETS + 1];
  58. AGLOBAL struct CreatureStruct  creature[CREATURES + 1];
  59.  
  60. AGLOBAL struct ObjectStruct object[LASTOBJECT + 1] =
  61. {   {2310,  30}, // AFFIXER
  62.     { 300,  30}, // AMMO
  63.     { 510,  30}, // ARMOUR
  64.     {1325,  30}, // AUTOJUMP
  65.     { 410,  30}, // BONUS
  66.     {1040,  30}, // BRAKES
  67.     {1000,  30}, // CONVERTER
  68.     { 880,  30}, // CUTTER
  69.     { 870,  30}, // CYCLONE_O
  70.     { 900,  30}, // ENCLOSER
  71.     { 305,  30}, // GLOW
  72.     { 555,  30}, // GROWER
  73.     {1600,  30}, // ICE
  74.     { 600,  30}, // LIGHTNING
  75.     {1600,  30}, // MAGNET
  76.     { 250,  30}, // MINIBOMB
  77.     { 900,  30}, // MINIHEALER
  78.     { 680,  30}, // MISSILE_O
  79.     {1100,  30}, // MULTIPLIER
  80.     { 745,  30}, // POWER
  81.     { 890,  30}, // PROTECTOR
  82.     { 660,  30}, // PULSE
  83.     { 875,  30}, // PUSHER
  84.     {1000,  30}, // REMNANT
  85.     {1200,  30}, // SIDESHOT
  86.     {1300,  30}, // SLAYER
  87.     {1600,  30}, // SLOWER
  88.     { 410,  30}, // SUPERBOMB
  89.     {7100,  30}, // SUPERHEALER
  90.     {1690,  30}, // SWITCHER
  91.     {3900,  30}, // TREASURE
  92.     {6200,  30}  // UMBRELLA
  93. };
  94.  
  95. AGLOBAL struct CreatureInfoStruct creatureinfo[SPECIES + 1] =
  96. { { ANT,        FALSE,  310, 17,  13,  50}, //  0
  97.   { BIRD,       FALSE,  500, 25,  12,  50}, //  1
  98.   { BULL,       FALSE,  640 ,30,   3,  50}, //  2
  99.   { CAMEL,      FALSE, 1090, 45,  16, 100}, //  3
  100.   { CLOUD,      FALSE,  300, 22,   8,  50}, //  4
  101.   { CYCLONE_C,  FALSE,    0,  0,   1, 100}, //  5
  102.   { DOG,        FALSE,  350, 12,   3,  50}, //  6
  103.   { FISH,       TRUE,   400, 32,   9,  50}, //  7
  104.   { FRAGMENT,   FALSE,    0,  0,   3,   0}, //  8
  105.   { FROG,       FALSE,  600, 27,   4,  50}, //  9
  106.   { GIRAFFE,    FALSE,  365,  7, 255,  50}, // 10
  107.   { KANGAROO,   FALSE,  750, 10,   9, 100}, // 11
  108.   { MISSILE_C,  FALSE,    0,  0,   6,  50}, // 12
  109.   { MONKEY,     FALSE,  470, 40,   7, 100}, // 13
  110.   { MOUSE,      FALSE,  290, 32,   9,  50}, // 14
  111.   { OCTOPUS,    TRUE,   450, 15,  14,  50}, // 15
  112.   { ORB,        FALSE,  195,  5,   5,  50}, // 16
  113.   { OTTER,      TRUE,     0,  0,  12, 100}, // 17
  114.   { RABBIT,     FALSE, 1060, 35,   3, 200}, // 18
  115.   { RAIN,       FALSE,    0,  0,   4,  50}, // 19
  116.   { SALAMANDER, FALSE,  320, 20,   9,  50}, // 20
  117.   { SNAIL,      FALSE,  260,  0,  50,  50}, // 21
  118.   { SPIDER,     FALSE,  850,  0,  17,  50}, // 22
  119.   { GOOSE,      FALSE,  990, 42,  25, 100}, // 23
  120.   { HORSE,      FALSE,  500, 37,   7,  50}, // 24
  121.   { BEAR,       TRUE,   450, 47,  10,  50}, // 25
  122.   { ELEPHANT,   FALSE,  500,  9,  18,  50}  // 26
  123. };
  124.  
  125. // 4. IMPORTED VARIABLES -------------------------------------------------
  126.  
  127. // 5. MODULE VARIABLES ---------------------------------------------------
  128.  
  129. MODULE ABOOL teleports,
  130.              trainer;
  131. MODULE UBYTE infector[MAXFIELDX + 1][MAXFIELDY + 1];
  132. MODULE TEXT  timedisplay[5];
  133.  
  134. // 6. MODULE STRUCTURES --------------------------------------------------
  135.  
  136. MODULE UBYTE eachworm[4][2][9] =
  137. { { { GREENHEAD_NW,  GREENHEADUP,   GREENHEAD_NE,
  138.       GREENHEADLEFT, ANYTHING,      GREENHEADRIGHT,
  139.       GREENHEAD_SW,  GREENHEADDOWN, GREENHEAD_SE
  140.     },
  141.     { GREENGLOW_NW,  GREENGLOWUP,   GREENGLOW_NE,
  142.       GREENGLOWLEFT, ANYTHING,      GREENGLOWRIGHT,
  143.       GREENGLOW_SW,  GREENGLOWDOWN, GREENGLOW_SE
  144.   } },
  145.   { { REDHEAD_NW,    REDHEADUP,     REDHEAD_NE,
  146.       REDHEADLEFT,   ANYTHING,      REDHEADRIGHT,
  147.       REDHEAD_SW,    REDHEADDOWN,   REDHEAD_SE
  148.     },
  149.     { REDGLOW_NW,    REDGLOWUP,     REDGLOW_NE,
  150.       REDGLOWLEFT,   ANYTHING,      REDGLOWRIGHT,
  151.       REDGLOW_SW,    REDGLOWDOWN,   REDGLOW_SE
  152.   } },
  153.   { { BLUEHEAD_NW,   BLUEHEADUP,    BLUEHEAD_NE,
  154.       BLUEHEADLEFT,  ANYTHING,      BLUEHEADRIGHT,
  155.       BLUEHEAD_SW,   BLUEHEADDOWN,  BLUEHEAD_SE
  156.     },
  157.     { BLUEGLOW_NW,   BLUEGLOWUP,    BLUEGLOW_NE,
  158.       BLUEGLOWLEFT,  ANYTHING,      BLUEGLOWRIGHT,
  159.       BLUEGLOW_SW,   BLUEGLOWDOWN,  BLUEGLOW_SE
  160.   } },
  161.   { { YELLOWHEAD_NW, YELLOWHEADUP,  YELLOWHEAD_NE,
  162.       YELLOWHEADLEFT,ANYTHING,      YELLOWHEADRIGHT,
  163.       YELLOWHEAD_SW, YELLOWHEADDOWN,YELLOWHEAD_SE
  164.     },
  165.     { YELLOWGLOW_NW, YELLOWGLOWUP,  YELLOWGLOW_NE,
  166.       YELLOWGLOWLEFT,ANYTHING,      YELLOWGLOWRIGHT,
  167.       YELLOWGLOW_SW, YELLOWGLOWDOWN,YELLOWGLOW_SE
  168. } } };
  169.  
  170. // 7. MODULE FUNCTIONS ---------------------------------------------------
  171.  
  172. MODULE void death(void);
  173. MODULE void fastloop(void);
  174. MODULE void killall(void);
  175. MODULE void magnetloop(void);
  176. MODULE void newhiscores(void);
  177. MODULE void slowloop(void);
  178. MODULE void ReadGameports(void);
  179. MODULE void endoflevel(void);
  180. MODULE void drawcause(SBYTE player, SBYTE state);
  181. MODULE void newlevel(UBYTE player);
  182. MODULE void ramming(SBYTE player);
  183. MODULE void wormworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2);
  184. MODULE SWORD atleast(SWORD value, SWORD minimum);
  185. MODULE ABOOL findempty(SBYTE* x, SBYTE* y, ABOOL mode);
  186. MODULE SBYTE slowdown(SBYTE speed, FLAG isworm, FLAG brakes);
  187. MODULE FLAG checkautojump(SBYTE player);
  188.  
  189. // 8. CODE ---------------------------------------------------------------
  190.  
  191. AGLOBAL ABOOL blockedtel(UBYTE which, SBYTE deltax, SBYTE deltay)
  192. {   if (blockedsquare(xwrap(teleport[partner(which)].x + deltax), ywrap(teleport[partner(which)].y + deltay)))
  193.     {   return TRUE;
  194.     } else
  195.     {   return FALSE;
  196. }   }
  197.  
  198. AGLOBAL void bombblast(UBYTE triggerer, SBYTE player, SBYTE centrex, SBYTE centrey, FLAG superbomb)
  199. {   SBYTE counter, strength,
  200.             uppy,   uppymax,
  201.            downy,  downymax,
  202.            leftx,  leftxmax,
  203.           rightx, rightxmax,
  204.                x,      y;
  205.  
  206.     effect(FXUSE_BOMB);
  207.  
  208.     if (superbomb)
  209.     {   strength = ADD_SUPERBOMB + arand(RAND_SUPERBOMB);
  210.     } else
  211.     {   strength = ADD_MINIBOMB  + arand(RAND_MINIBOMB );
  212.     }
  213.     leftxmax = centrex - strength;
  214.     if (leftxmax < 0)
  215.         leftxmax = 0;
  216.     rightxmax = centrex + strength;
  217.     if (rightxmax > fieldx)
  218.         rightxmax = fieldx;
  219.     uppymax = centrey - strength;
  220.     if (uppymax < 0)
  221.         uppymax = 0;
  222.     downymax = centrey + strength;
  223.     if (downymax > fieldy)
  224.         downymax = fieldy;
  225.  
  226.     leftx = centrex;
  227.     rightx = centrex;
  228.     uppy = centrey;
  229.     downy = centrey;
  230.     for (counter = 1; counter <= strength; counter++)
  231.     {   if (leftx > leftxmax)
  232.         {   leftx--;
  233.             for (y = uppy; y <= downy; y++)
  234.                 squareblast(triggerer, player, field[leftx][y],  leftx,  y,     FALSE, superbomb);
  235.         }
  236.         if (uppy > uppymax)
  237.         {   uppy--;
  238.             for (x = leftx; x <= rightx; x++)
  239.                 squareblast(triggerer, player, field[x][uppy],   x,      uppy,  FALSE, superbomb);
  240.         }
  241.         if (rightx < rightxmax)
  242.         {   rightx++;
  243.             for (y = downy; y >= uppy; y--)
  244.                 squareblast(triggerer, player, field[rightx][y], rightx, y,     FALSE, superbomb);
  245.         }
  246.         if (downy < downymax)
  247.         {   downy++;
  248.             for (x = rightx; x >= leftx; x--)
  249.                 squareblast(triggerer, player, field[x][downy],  x,      downy, FALSE, superbomb);
  250. }   }   }
  251.  
  252. AGLOBAL SBYTE bsign(SBYTE value)
  253. {   if (value < 0)
  254.         return (-1);
  255.     elif (value > 0)
  256.         return (1);
  257.     else return (0);
  258. }
  259.  
  260. AGLOBAL void changefield(void)
  261. {   SBYTE x, y;
  262.  
  263.     if (randomflag && a == PLAYGAME && level)
  264.     {   do
  265.         {    sourcelevel = arand(levels - 1) + 1;
  266.         } while (randomarray[sourcelevel]);
  267.         randomarray[sourcelevel] = TRUE;
  268.     } else sourcelevel = level;
  269.  
  270.     for (x = 0; x <= fieldx; x++)
  271.         for (y = 0; y <= fieldy; y++)
  272.             field[x][y] = EMPTY; // slow method
  273.  
  274.     for (x = 0; x <= MINFIELDX; x++)
  275.         for (y = 0; y <= MINFIELDY; y++)
  276.             field[x + LEFTGAP][y + TOPGAP] = board[sourcelevel][x][y];
  277. }
  278.  
  279. void clearhiscores(void)
  280. {   SBYTE i;
  281.  
  282.     clearthem = FALSE;
  283.     for (i = 0; i <= HISCORES; i++)
  284.     {   hiscore[i].player = -1;
  285.         hiscore[i].level = 0;
  286.         hiscore[i].score = 0;
  287.         hiscore[i].fresh = FALSE;
  288.         hiscore[i].name[0] = 0;
  289.         hiscore[i].time[0] = 0;
  290.         hiscore[i].date[0] = 0;
  291. }   }
  292.  
  293. MODULE void death(void)
  294. {   SBYTE pain, player;
  295.     UBYTE which;
  296.  
  297.     for (player = 0; player <= 3; player++)
  298.     {   if (worm[player].lives)
  299.         {   if (!worm[player].alive)
  300.             {   pain = 0;
  301.                 if (worm[player].cause >= FIRSTTAIL && worm[player].cause <= LASTTAIL)
  302.                 {   if (player == worm[player].cause - FIRSTTAIL)
  303.                         pain = PAIN_FRIENDLYTAIL;
  304.                     else pain = PAIN_ENEMYTAIL;
  305.                 } elif (worm[player].cause >= FIRSTGLOW && worm[player].cause <= LASTGLOW)
  306.                 {   pain = PAIN_GLOW;
  307.                 } elif (worm[player].cause >= FIRSTFIRE && worm[player].cause <= LASTFIRE)
  308.                     pain = PAIN_WORMFIRE;
  309.                 elif (worm[player].cause >= FIRSTHEAD && worm[player].cause <= LASTHEAD)
  310.                     pain = PAIN_HEAD;
  311.                 elif (worm[player].cause >= FIRSTPROTECTOR && worm[player].cause <= LASTPROTECTOR)
  312.                     pain = PAIN_PROTECTOR;
  313.                 elif
  314.                 (   worm[player].cause >= FIRSTCREATURE
  315.                  || (worm[player].cause >= FIRSTRAIN    && worm[player].cause <= LASTRAIN   )
  316.                  || (worm[player].cause >= FIRSTMISSILE && worm[player].cause <= LASTMISSILE)
  317.                 )
  318.                 {   pain = PAIN_CREATURE;
  319.                 } else switch (worm[player].cause)
  320.                 {
  321.                 case METAL:
  322.                     pain = PAIN_METAL;
  323.                 break;
  324.                 case SLIME:
  325.                     pain = PAIN_SLIME;
  326.                 break;
  327.                 case STONE:
  328.                     pain = PAIN_STONE;
  329.                 break;
  330.                 case TELEPORT:
  331.                     pain = PAIN_TELEPORT;
  332.                 break;
  333.                 case WOOD:
  334.                     pain = PAIN_WOOD;
  335.                 break;
  336.                 case MINIBOMB:
  337.                 case SUPERBOMB:
  338.                     pain = PAIN_BOMB;
  339.                 break;
  340.                 case SLAYER:
  341.                     pain = PAIN_SLAYER;
  342.                 break;
  343.                 default:
  344.                     // assert(0);
  345.                 break;
  346.                 }
  347.                 if (pain > worm[player].lives)
  348.                     worm[player].lives = 0;
  349.                 else worm[player].lives -= pain;
  350.  
  351.                 draw(worm[player].x, worm[player].y, FIRSTPAIN + player);
  352.                 drawcause(player, NORMAL);
  353.                 stat(player, MINIHEALER);
  354.                 if (level)
  355.                     worm[player].levelreached = level;
  356.                 else worm[player].levelreached = reallevel;
  357.                 if (worm[player].lives)
  358.                 {   effect(FXPAIN + player);
  359.                     worm[player].alive = TRUE;
  360.                     worm[player].causewait = r + CAUSEWAIT;
  361.                 } else
  362.                 {   /* kill worm */
  363.                     effect(FXDEATH_WORM);
  364.                     change(worm[player].x, worm[player].y, FIRSTGRAVE + player);
  365.                     updatearrow(worm[player].y);
  366.                     for (which = 0; which <= PROTECTORS; which++)
  367.                         if (protector[player][which].alive && protector[player][which].visible)
  368.                             change(protector[player][which].x, protector[player][which].y, EMPTY);
  369.                     for (which = 0; which <= MAGNETS; which++)
  370.                         if (magnet[which].player == player)
  371.                             magnet[which].alive = FALSE;
  372.                     if (worm[player].score >= worm[player].hiscore)
  373.                         worm[player].hiscore = worm[player].score;
  374.     }   }   }   }
  375.  
  376.     if (!worm[0].lives && !worm[1].lives && !worm[2].lives && !worm[3].lives)
  377.     {   /* End of game */
  378.         for (player = 0; player <= 3; player++)
  379.             if (worm[player].control != NONE && worm[player].score >= worm[player].hiscore)
  380.                 worm[player].hiscore = worm[player].score;
  381.         newhiscores();
  382.         effect(FXGAMEOVER);
  383.  
  384.         playsong(1);
  385.  
  386.         a = GAMEOVER;
  387.         say((STRPTR) "Game over!", WHITE);
  388.         waitasec();
  389.         anykey(FALSE);
  390. }   }
  391.  
  392. MODULE void drawcause(SBYTE player, SBYTE state)
  393. {   if (state == BLACK)
  394.     {   draw
  395.         (   -6,
  396.             (player * 10) + 7,
  397.             BLACKENED
  398.         );
  399.     } else
  400.     {   draw
  401.         (   -6,
  402.             (player * 10) + 7,
  403.             worm[player].cause
  404.         );
  405. }   }
  406.  
  407. /* NAME    enginesetup -- once-only initialization of engine variables
  408. SYNOPSIS   enginesetup(void);
  409. FUNCTION   Sets up the unchanging worm variables.
  410. MODULE     engine.c */
  411.  
  412. void enginesetup(void)
  413. {   worm[0].statx = worm[0].staty = worm[1].staty = worm[2].statx = 0;
  414.     worm[1].statx = worm[2].staty = worm[3].statx = worm[3].staty = 1;
  415.     worm[0].colour = GREEN;
  416.     worm[1].colour = RED;
  417.     worm[2].colour = BLUE;
  418.     worm[3].colour = YELLOW;
  419.     worm[0].dimcolour = DARKGREEN;
  420.     worm[1].dimcolour = DARKRED;
  421.     worm[2].dimcolour = DARKBLUE;
  422.     worm[3].dimcolour = DARKYELLOW;
  423.     worm[0].port = 2;
  424.     worm[1].port = 3;
  425.     worm[2].port = 1;
  426.     worm[3].port = 0;
  427.     worm[0].name[0] =
  428.     worm[1].name[0] =
  429.     worm[2].name[0] =
  430.     worm[3].name[0] = 0;
  431.  
  432.     strcpy(pathname, DEFAULTSET);
  433.  
  434.     engraving = 0; // you can't use rand() in this function, it is called too early in the startup by SAS/C. 
  435.  
  436.     systemsetup();
  437. }
  438.  
  439. MODULE void fastloop(void)
  440. {   SBYTE i, player, x, y;
  441.  
  442.     // decrement score if stopped
  443.     for (player = 0; player <= 3; player++)
  444.     {   if
  445.         (   worm[player].lives
  446.          && worm[player].speed == 0
  447.          && worm[player].score >= worm[player].multi * players
  448.         )
  449.         {   wormscore(player, -1);
  450.     }   }
  451.  
  452.     // animate
  453.     if (anims)
  454.     {   for (i = 0; i <= CREATURES; i++)
  455.         {   if (creature[i].alive && creature[i].visible)
  456.             {   if (creature[i].species == BIRD)
  457.                 {   if (!(r % ANIMSPEED_BIRD))
  458.                     {   creature[i].frame += creature[i].dir;
  459.                         drawcreature(i);
  460.                         if (creature[i].frame == 0)
  461.                         {   creature[i].dir = 1;
  462.                         } elif (creature[i].frame == 4)
  463.                         {   creature[i].dir = -1;
  464.                 }   }   }
  465.                 elif (creature[i].species == MISSILE_C)
  466.                 {   if (!(r % ANIMSPEED_MISSILE))
  467.                     {   drawcreature(i);
  468.                         if (++creature[i].frame > MISSILEFRAMES)
  469.                         {   creature[i].frame = 0;
  470.                 }   }   }
  471.                 elif (creature[i].species == FRAGMENT && creature[i].subspecies == BANANA)
  472.                 {   if (!(r % ANIMSPEED_BANANA))
  473.                     {   if (creature[i].frame == 0 && creature[i].dir == -1)
  474.                         {   creature[i].frame = 7;
  475.                         } elif (creature[i].frame == 7 && creature[i].dir == 1)
  476.                         {   creature[i].frame = 0;
  477.                         } else creature[i].frame += creature[i].dir;
  478.                         drawcreature(i);
  479.     }   }   }   }   }
  480.  
  481.     if (banging)
  482.     {   banging = FALSE;
  483.         for (x = 0; x <= fieldx; x++)
  484.             for (y = 0; y <= fieldy; y++)
  485.                 if (field[x][y] == BANGDYNAMITE)
  486.                 {   change(x, y, SILVER);
  487.                     bangdynamite(x, y, infector[x][y]);
  488.                 }
  489.         for (x = 0; x <= fieldx; x++)
  490.             for (y = 0; y <= fieldy; y++)
  491.                 if (field[x][y] == TEMPBANGDYNAMITE)
  492.                 {   banging = TRUE;
  493.                     field[x][y] = BANGDYNAMITE;
  494.     }           }
  495.  
  496.     // flash letter
  497.     if (level)
  498.     {   if (r % 8 == 1)
  499.         {   draw(numberx, numbery, WHITENED);
  500.         } elif (r % 8 == 2)
  501.         {   draw(numberx, numbery, FIRSTNUMBER + number - 1);
  502.     }   }
  503.  
  504.     // flash icons
  505.     for (player = 0; player <= 3; player++)
  506.     {   if (worm[player].control != NONE)
  507.         {   icon(player, GLOW);
  508.             icon(player, CUTTER);
  509.             icon(player, ARMOUR);
  510. }   }   }
  511.  
  512. MODULE ABOOL findempty(SBYTE* x, SBYTE* y, ABOOL mode)
  513. {   SBYTE xx, yy;
  514.     UBYTE c;
  515.  
  516.     if (mode)
  517.     {   do
  518.         {   xx = arand(fieldx);
  519.             yy = arand(fieldy);
  520.             c  = field[xx][yy];
  521.         } while
  522.         (    c != SLIME
  523.          &&  c != WOOD
  524.          &&  c != STONE
  525.          &&  c != METAL
  526.          && (c < FIRSTTAIL || c > LASTTAIL)
  527.         ); // theoretical chance of infinite loop here
  528.     } else
  529.     {   do
  530.         {   xx = arand(fieldx);
  531.             yy = arand(fieldy);
  532.             c  = field[xx][yy];
  533.         } while (c < FIRSTEMPTY || c > LASTEMPTY); // theoretical chance of infinite loop here
  534.     }
  535.  
  536.     *x = xx;
  537.     *y = yy;
  538.     return(TRUE);
  539. }
  540.  
  541. void gameloop(void)
  542. {   SBYTE i, player;
  543.  
  544.     if (a == PLAYGAME)
  545.     {   ReadGameports();
  546.         fastloop();
  547.         gameinput();
  548.     }
  549.     if (a == PLAYGAME)
  550.     {   ReadGameports();
  551.         for (player = 0; player <= 3; player++)
  552.         {   if (worm[player].lives)
  553.             {   if (worm[player].speed)
  554.                 {   if (!(r % worm[player].speed))
  555.                     {   if (worm[player].wait)
  556.                         {   worm[player].wait = FALSE;
  557.                         } else wormloop(player);
  558.                 }   }
  559.                 else
  560.                 {   stoppedwormloop(player);
  561.     }   }   }   }
  562.     if (a == PLAYGAME && !ice)
  563.     {   ReadGameports();
  564.         for (i = 0; i <= CREATURES; i++)
  565.         {   if (creature[i].alive)
  566.             {   if (creature[i].species == BULL && creature[i].deltax == 0)
  567.                 {   for (player = 0; player <= 3; player++)
  568.                     {   if (worm[player].lives && worm[player].y == creature[i].y)
  569.                         {   if (creature[i].dir == -1)
  570.                             {   if (worm[player].x < creature[i].x)
  571.                                 {   creature[i].deltax = -1;
  572.                             }   }
  573.                             else
  574.                             {   // assert(creature[i].dir == 1);
  575.                                 if (worm[player].x > creature[i].x)
  576.                                 {   creature[i].deltax = 1;
  577.                 }   }   }   }   }
  578.                 if (!(r % creature[i].speed))
  579.                 {   creatureloop(i);
  580.     }   }   }   }
  581.     if (a == PLAYGAME)
  582.     {   ReadGameports();
  583.         if (!(r % SPEED_MAGNET))
  584.         {   magnetloop();
  585.         }
  586.         death();
  587.     }
  588.     if (a == PLAYGAME)
  589.     {   ReadGameports();
  590.         if (!(r % VERYSLOW))
  591.         {   slowloop();
  592. }   }   }
  593.  
  594.  
  595. MODULE void killall(void)
  596. {   UBYTE i;
  597.  
  598.     for (i = 0; i <= CREATURES; i++)
  599.         creature[i].alive = FALSE;
  600.     for (i = 0; i <= MAGNETS; i++)
  601.         magnet[i].alive = FALSE;
  602.     teleports = FALSE;
  603. }
  604.  
  605. SBYTE loadfields(STRPTR fieldname)
  606. {   SBYTE i, j;
  607.     UBYTE IOBuffer[NAMELENGTH + 1];
  608.  
  609.     /* This routine is not entirely robust, especially regarding
  610.     failures part way through reading. It is very trusting of its data;
  611.     ie. it doesn't do any sanity checking.
  612.  
  613.     Provided that the fieldset was created with Worm Wars's built-in field
  614.     editor, and the file is not corrupt, these failures should never
  615.     happen anyway.
  616.  
  617.     open file */
  618.  
  619.     // say("Opening...", WHITE);
  620.  
  621.     if (!ZOpen(fieldname, FALSE))
  622.         return 1; /* no harm done */
  623.  
  624.     /* read header
  625.  
  626.     say("Reading header...", WHITE);
  627.  
  628.     FSET 7.4#!
  629.     0123456789
  630.  
  631.     # is the NULL terminator
  632.     ! is levels */
  633.  
  634.     if (!ZRead(IOBuffer, 10))
  635.     {    ZClose();
  636.         return 2; /* no harm done */
  637.     }
  638.     if (strcmp((STRPTR) IOBuffer, "FSET 7.5"))
  639.     {   ZClose();
  640.         return 3; /* no harm done */
  641.     }
  642.     levels = IOBuffer[9];
  643.  
  644.     /* read high score table */
  645.  
  646.     // say("Reading high score table...", WHITE);
  647.  
  648.     for (i = 0; i <= HISCORES; i++)
  649.     {   if (!ZRead(IOBuffer, 6))
  650.         {    ZClose();
  651.              return 4; /* incorrect levels */
  652.         }
  653.         hiscore[i].fresh                        =  FALSE;
  654.         hiscore[i].player                       =  IOBuffer[0];
  655.         hiscore[i].level                        =  IOBuffer[1];
  656.         hiscore[i].score                        = (IOBuffer[2] * 16777216)
  657.                                                 + (IOBuffer[3] * 65536)
  658.                                                 + (IOBuffer[4] * 256)
  659.                                                 +  IOBuffer[5];
  660.  
  661.         if (!ZRead(IOBuffer, NAMELENGTH + 1))
  662.         {   ZClose();
  663.             return 5; /* incorrect levels, corrupted high scores */
  664.         }
  665.         for (j = 0; j <= NAMELENGTH; j++)
  666.         {   hiscore[i].name[j]              = IOBuffer[j];
  667.         }
  668.         if (!ZRead(IOBuffer, TIMELENGTH + 1))
  669.         {   ZClose();
  670.             return 6; /* incorrect levels, corrupted high scores */
  671.         }
  672.         for (j = 0; j <= TIMELENGTH; j++)
  673.         {   hiscore[i].time[j]      = IOBuffer[j];
  674.         }
  675.         if (!ZRead(IOBuffer, DATELENGTH + 1))
  676.         {   ZClose();
  677.             return 7; /* incorrect levels, corrupted high scores */
  678.         }
  679.         for (j = 0; j <= DATELENGTH; j++)
  680.         {   hiscore[i].date[j]      = IOBuffer[j];
  681.     }   }
  682.  
  683.     // say("Reading level data...", WHITE);
  684.  
  685.     /* read level data */
  686.  
  687.     for (i = 0; i <= levels; i++)
  688.     {   if (!ZRead(IOBuffer, 8))
  689.         {   ZClose();
  690.             return 9;
  691.             /* incorrect levels, corrupted high scores,
  692.             incorrect startx, field data */
  693.         }
  694.         startx[i] = IOBuffer[0];
  695.         starty[i] = IOBuffer[1];
  696.  
  697.         if (!ZRead((UBYTE *) &board[i][0][0], LEVELSIZE))
  698.         {   ZClose();
  699.             return 10;
  700.             /* incorrect levels, corrupted high scores,
  701.             incorrect startx, field data */
  702.     }   }
  703.  
  704.     // say("Open done.", WHITE);
  705.  
  706.     // no need to read version string
  707.     ZClose();
  708.     modified = FALSE;
  709.     return 0;
  710. }
  711.  
  712. MODULE void magnetloop(void)
  713. {   SBYTE i;
  714.     UBYTE c;
  715.  
  716.     for (i = 0; i <= MAGNETS; i++)
  717.     {   if (magnet[i].alive)
  718.         {   // ensure magnet is still valid
  719.             if (field[magnet[i].x][magnet[i].y] != magnet[i].object)
  720.             {   magnet[i].alive = FALSE;
  721.             } else
  722.             {   change(magnet[i].x, magnet[i].y, EMPTY);
  723.                 magnet[i].x += bsign(worm[magnet[i].player].x - magnet[i].x);
  724.                 magnet[i].y += bsign(worm[magnet[i].player].y - magnet[i].y);
  725.                 c = field[magnet[i].x][magnet[i].y];
  726.  
  727.                 if
  728.                 (   (c >= FIRSTEMPTY && c <= LASTEMPTY)
  729.                  || (c >= FIRSTTAIL  && c <= LASTTAIL)
  730.                  || (c >= FIRSTGLOW  && c <= LASTGLOW)
  731.                 )
  732.                 {   change(magnet[i].x, magnet[i].y, magnet[i].object);
  733.                 } elif (c >= FIRSTHEAD && c <= LASTHEAD)
  734.                 {   change(magnet[i].x, magnet[i].y, magnet[i].object);
  735.                     wormscore(c - FIRSTHEAD, wormobject(c - FIRSTHEAD, magnet[i].x, magnet[i].y));
  736.                     drawhead(magnet[i].player);
  737.                 } else magnet[i].alive = FALSE;
  738. }   }   }   }
  739.  
  740. AGLOBAL void newfield(void)
  741. {   SBYTE x, y;
  742.  
  743.     startx[level] = CENTREX;
  744.     starty[level] = CENTREY;
  745.  
  746.     if (level)
  747.     {   for (x = 0; x <= fieldx; x++)
  748.         {   for (y = 0; y <= fieldy; y++)
  749.             {   board[level][x][y] = EMPTY;
  750.     }   }   }
  751.     else
  752.     {   for (x = 0; x <= fieldx; x++)
  753.         {   for (y = 0; y <= fieldy; y++)
  754.             {   board[0][x][y] = SILVER;
  755. }   }   }   }
  756.  
  757. void newfields(void)
  758. {   if (verify())
  759.     {   strcpy(pathname, DEFAULTSET);
  760.         levels = DEFAULTLEVELS;
  761.         modified = FALSE;
  762.         for (level = 0; level <= levels; level++)
  763.             newfield();
  764.         clearhiscores();
  765.         level = 1;
  766.         if (a == FIELDEDIT)
  767.         {   turborender();
  768.             saylevel(WHITE);
  769.         } else hiscores();
  770. }   }
  771.  
  772. void newgame(void)
  773. {   SBYTE i, player;
  774.  
  775.     players = 0;
  776.     for (player = 0; player <= 3; player++)
  777.     {   if (worm[player].control != NONE)
  778.             players++;
  779.         worm[player].lives = 0;
  780.         worm[player].speed = NORMAL;
  781.         worm[player].hiscore = 0;
  782.     }
  783.     for (i = 1; i <= MAXLEVELS; i++)
  784.     {   randomarray[i] = FALSE;
  785.     }
  786.  
  787.     r         = -1;
  788.     trainer   =
  789.     turbo     = FALSE;
  790.     ice       = 0;
  791.     reallevel = 0;
  792.     level     = 1;
  793.     a         = PLAYGAME;
  794.     clearscreen();
  795.     newlevel(arand(3));
  796.  
  797.     timing();
  798. }
  799.  
  800. MODULE void newhiscores(void)
  801. {   PERSIST TEXT  amiganame[4][NAMELENGTH + 1] = {"Jay Miner", "Carl Sassenrath", "R. J. Mical", "Dave Morse"};
  802.     AUTO    SBYTE i, j, player;
  803.  
  804.     datestamp();
  805.     for (player = 0; player <= 3; player++)
  806.     {   for (i = 0; i <= HISCORES; i++)
  807.         {   if (worm[player].control != NONE && worm[player].score >= hiscore[i].score)
  808.             {   /* push all worse hiscores down */
  809.  
  810.                 if (i < HISCORES)
  811.                 {   for (j = HISCORES; j >= i + 1; j--)
  812.                     {   hiscore[j].player     = hiscore[j - 1].player;
  813.                         hiscore[j].level      = hiscore[j - 1].level;
  814.                         hiscore[j].score      = hiscore[j - 1].score;
  815.                         hiscore[j].fresh      = hiscore[j - 1].fresh;
  816.                         strcpy(hiscore[j].name, hiscore[j - 1].name);
  817.                         strcpy(hiscore[j].date, hiscore[j - 1].date);
  818.                         strcpy(hiscore[j].time, hiscore[j - 1].time);
  819.                 }   }
  820.  
  821.                 modified = TRUE;
  822.                 hiscore[i].player = player;
  823.                 hiscore[i].level  = worm[player].levelreached;
  824.                 hiscore[i].score  = worm[player].hiscore;
  825.                 if (worm[player].control == AMIGA)
  826.                 {   strcpy(hiscore[i].name, amiganame[player]);
  827.                     hiscore[i].fresh = FALSE;
  828.                 } else
  829.                 {   strcpy(hiscore[i].name, "(New)");
  830.                     hiscore[i].fresh = TRUE;
  831.                 }
  832.                 strcpy(hiscore[i].time, times);
  833.                 strcpy(hiscore[i].date, date);
  834.                 break; /* vital */
  835. }   }   }   }
  836.  
  837. MODULE void newlevel(UBYTE player)
  838. {   SBYTE delays, i, j;
  839.  
  840.     if (level >= 2)
  841.         enginerundown(player); // enginerundown() could easily be incorporated directly into newlevel()
  842.     if (a == PLAYGAME)
  843.     {   say("", BLACK);
  844.         if (engraving == 8)
  845.         {   engraving = 0;
  846.         } else
  847.         {   engraving++;
  848.         }
  849.  
  850.         if (level > levels)
  851.         {   for (i = 0; i <= 3; i++)
  852.             {   if (worm[i].lives)
  853.                     worm[i].levelreached = -1;
  854.                 if (worm[player].control != NONE && worm[player].score >= worm[player].hiscore)
  855.                     worm[player].hiscore = worm[player].score;
  856.             }
  857.             celebrate();
  858.             newhiscores();
  859.         } else
  860.         {   saylevel(WHITE);
  861.  
  862.             for (i = 0; i <= 3; i++)
  863.             {   if (worm[i].multi > 1)
  864.                 {   worm[i].multi /= 2;
  865.             }   }
  866.             killall();
  867.             turborender();
  868.  
  869.             if (level == 0)
  870.             {   playsong(3);
  871.             } else
  872.             {   playsong(4 + (level % 3));
  873.             }
  874.             for (i = 0; i <= 3; i++)
  875.             {   worm[i].speed = NORMAL;
  876.                 if (worm[i].lives)
  877.                     stat(i, BRAKES);
  878.                 worm[i].moved = FALSE;
  879.                 worm[i].numbers = 0;
  880.                 worm[i].x = startx[sourcelevel] + LEFTGAP;
  881.                 worm[i].y = starty[sourcelevel] + TOPGAP;
  882.                 worm[i].arrowy = worm[i].y;
  883.         switch(i)
  884.         {
  885.         case 0:
  886.             worm[0].deltax = -1;
  887.             worm[0].deltay = 0;
  888.         break;
  889.         case 1:
  890.             worm[1].deltax = 1;
  891.             worm[1].deltay = 0;
  892.         break;
  893.         case 2:
  894.             worm[2].deltax = 0;
  895.             worm[2].deltay = -1;
  896.         break;
  897.         case 3:
  898.             worm[3].deltax = 0;
  899.             worm[3].deltay = 1;
  900.         break;
  901.         default:
  902.         break;
  903.             }   }
  904.             if
  905.             (   (worm[0].control != NONE && worm[0].control != AMIGA)
  906.              || (worm[1].control != NONE && worm[1].control != AMIGA)
  907.              || (worm[2].control != NONE && worm[2].control != AMIGA)
  908.              || (worm[3].control != NONE && worm[3].control != AMIGA)
  909.             )
  910.             {   turbo = FALSE;
  911.             }
  912.             delay = DELAY;
  913.             delays = level / 5;
  914.             if (delays)
  915.             {   for (i = 1; i <= delays; i++)
  916.                 {   delay = delay * 19 / 20;
  917.             }   }
  918.  
  919.             if (level)
  920.             {   secondsperlevel = SECONDSPERLEVEL;
  921.  
  922.                 number = 1;
  923.                 putnumber();
  924.                 for (i = 0; i <= 3; i++)
  925.                 {   if (!worm[i].lives && worm[i].control != NONE)
  926.                     {   /* create (or resurrect) a worm */
  927.  
  928.                         worm[i].lives      = STARTLIVES;
  929.                         worm[i].alive      = TRUE;
  930.                         worm[i].multi      = 1;
  931.                         worm[i].causewait  = (ULONG) -1;
  932.                         worm[i].last       = FIRSTTAIL + i;
  933.                         worm[i].nextlife   = LIFEMODULO;
  934.  
  935.                         worm[i].pos        = -1;
  936.  
  937.                         worm[i].remnants   =
  938.                         worm[i].affixer    =
  939.                         worm[i].sideshot   =
  940.                         worm[i].pusher     =
  941.                         worm[i].flashed    =
  942.                         worm[i].encloser   =
  943.                         worm[i].rammed     =
  944.                         worm[i].frosted    =
  945.                         worm[i].wait       =
  946.                         worm[i].autojump   =
  947.                         worm[i].brakes     = FALSE;
  948.  
  949.                         worm[i].score      =
  950.                         worm[i].oldscore   =
  951.                         worm[i].armour     =
  952.                         worm[i].power      =
  953.                         worm[i].ammo       =
  954.                         worm[i].glow       =
  955.                         worm[i].cutter     =
  956.                         worm[i].olddeltax  =
  957.                         worm[i].olddeltay  = 0;
  958.  
  959.                         for (j = 0; j <= PROTECTORS; j++)
  960.                         {   protector[i][j].alive = FALSE;
  961.                         }
  962.                         for (j = 0; j <= LASTOBJECT; j++)
  963.                         {   stat(i, j);
  964.             }   }   }   }
  965.             for (i = 0; i <= 3; i++)
  966.             {   if (worm[i].control != NONE)
  967.                 {   for (j = 0; j <= LASTOBJECT; j++)
  968.                     {   icon(i, j);
  969.     }   }   }   }   }
  970.     stopfx();
  971.     clearkybd();
  972.     resettime();
  973. }
  974.  
  975. AGLOBAL SBYTE partner(SBYTE which)
  976. {   if (which % 2 == 0)
  977.         return((SBYTE) (which + 1));
  978.     else return((SBYTE) (which - 1));
  979. }
  980.  
  981. AGLOBAL void putnumber(void)
  982. {   SBYTE oldnumbery = numbery;
  983.     ABOOL done;
  984.  
  985.     do
  986.     {   done = findempty(&numberx, &numbery, FALSE);
  987.     } while (!done);
  988.     change(numberx, numbery, FIRSTNUMBER + number - 1);
  989.     updatearrow(oldnumbery);
  990.     updatearrow(numbery);
  991. }
  992.  
  993. AGLOBAL void reflect(UBYTE which)
  994. {   creature[which].deltax  = -creature[which].deltax;
  995.     creature[which].deltay  = -creature[which].deltay;
  996.     creature[which].x      +=  creature[which].deltax * 2;
  997.     creature[which].y      +=  creature[which].deltay * 2;
  998. }
  999.  
  1000. ABOOL savefields(STRPTR fieldname)
  1001. {   SBYTE i, j;
  1002.     UBYTE IOBuffer[NAMELENGTH + 1];
  1003.  
  1004.     if (!ZOpen(fieldname, TRUE))
  1005.     {   return FALSE;
  1006.     }
  1007.  
  1008.     /* write header */
  1009.  
  1010.     strcpy((STRPTR) IOBuffer, "FSET 7.5");
  1011.     IOBuffer[9] = levels;
  1012.     if (!ZWrite(IOBuffer, 10))
  1013.     {   ZClose();
  1014.         return FALSE;
  1015.     }
  1016.  
  1017.     /* write high score table */
  1018.  
  1019.     for (i = 0; i <= HISCORES; i++)
  1020.     {   IOBuffer[0]                                             =  hiscore[i].player;
  1021.         IOBuffer[1]                                             =  hiscore[i].level;
  1022.  
  1023.         IOBuffer[2]                                             =   hiscore[i].score / 16777216;
  1024.         IOBuffer[3]                                             =  (hiscore[i].score % 16777216) / 65536;
  1025.         IOBuffer[4]                                             = ((hiscore[i].score % 16777216) % 65536) / 256;
  1026.         IOBuffer[5]                                             = ((hiscore[i].score % 16777216) % 65536) % 256;
  1027.         if (!ZWrite(IOBuffer, 6))
  1028.         {   ZClose();
  1029.             return FALSE;
  1030.         }
  1031.  
  1032.         for (j = 0; j <= NAMELENGTH; j++)
  1033.             IOBuffer[j]                                         = hiscore[i].name[j];
  1034.         if (!ZWrite(IOBuffer, NAMELENGTH + 1))
  1035.         {   ZClose();
  1036.             return FALSE;
  1037.         }
  1038.         for (j = 0; j <= TIMELENGTH; j++)
  1039.             IOBuffer[j]                                             = hiscore[i].time[j];
  1040.         if (!ZWrite(IOBuffer, TIMELENGTH + 1))
  1041.         {   ZClose();
  1042.             return FALSE;
  1043.         }
  1044.         for (j = 0; j <= DATELENGTH; j++)
  1045.             IOBuffer[j]                                             = hiscore[i].date[j];
  1046.         if (!ZWrite(IOBuffer, DATELENGTH + 1))
  1047.         {   ZClose();
  1048.             return FALSE;
  1049.     }   }
  1050.  
  1051.     /* write level data */
  1052.  
  1053.     for (i = 0; i <= levels; i++)
  1054.     {   IOBuffer[0] = startx[i];
  1055.         IOBuffer[1] = starty[i];
  1056.         IOBuffer[2] =
  1057.         IOBuffer[3] =
  1058.         IOBuffer[4] =
  1059.         IOBuffer[5] =
  1060.         IOBuffer[6] =
  1061.         IOBuffer[7] = 0;
  1062.  
  1063.         if (!ZWrite(IOBuffer, 8))
  1064.         {   ZClose();
  1065.             return FALSE;
  1066.         }
  1067.  
  1068.         if (!ZWrite((UBYTE *) &board[i][0][0], LEVELSIZE))
  1069.         {   ZClose();
  1070.             return FALSE;
  1071.     }   }
  1072.  
  1073.     /* write version string */
  1074.  
  1075.     if (!ZWrite((UBYTE *) VERSION, strlen(VERSION)))
  1076.     {   ZClose();
  1077.         return FALSE;
  1078.     }
  1079.  
  1080.     ZClose();
  1081.  
  1082.     if (clearthem)
  1083.         clearhiscores();
  1084.     modified = FALSE;
  1085.     return TRUE;
  1086. }
  1087.  
  1088. void saylevel(COLOUR colour)
  1089. {   TEXT mainstring[15] = "Level ", tempstring[4];
  1090.  
  1091.     if (level > 0)
  1092.     {   stci_d(&mainstring[6], level);
  1093.         strcat((char*) mainstring, " of ");
  1094.         stci_d(tempstring, levels);
  1095.         strcat((char*) mainstring, (char*) tempstring);
  1096.         say(mainstring, colour);
  1097.     } else
  1098.     {   say("Bonus Level", colour);
  1099. }   }
  1100.  
  1101. MODULE SBYTE slowdown(SBYTE speed, FLAG isworm, FLAG brakes)
  1102. {   speed *= 2;
  1103.     if (isworm && speed > SLOW)
  1104.     {   if (brakes)
  1105.         {   speed = 0;
  1106.         } else speed = SLOW;
  1107.     }
  1108.     return(speed);
  1109. }
  1110.  
  1111. MODULE void slowloop(void)
  1112. {   SBYTE i, j, player, which, x, xx, y, yy;
  1113.     UBYTE c;
  1114.     ABOOL done, ok;
  1115.     UWORD chance;
  1116.  
  1117.     if (ice)
  1118.     {   ice--;
  1119.     }
  1120.  
  1121.     /* decrement worm strength */
  1122.  
  1123.     for (player = 0; player <= 3; player++)
  1124.     {   if (worm[player].lives)
  1125.         {   if (worm[player].cutter > 0)
  1126.             {   worm[player].cutter--;
  1127.                 icon(player, CUTTER);
  1128.             }
  1129.             if (worm[player].glow > 0)
  1130.             {   worm[player].glow--;
  1131.                 icon(player, GLOW);
  1132.             }
  1133.             if (worm[player].armour > 0)
  1134.             {   worm[player].armour--;
  1135.                 icon(player, ARMOUR);
  1136.     }   }   }
  1137.  
  1138.     /* blank out old causes */
  1139.  
  1140.     for (player = 0; player <= 3; player++)
  1141.     {   if (worm[player].lives > 0 && r > worm[player].causewait)
  1142.         {   drawcause(player, BLACK);
  1143.             worm[player].causewait = (ULONG) -1; /* most future time possible */
  1144.     }   }
  1145.  
  1146.     if (!ice)
  1147.     {   if (level)
  1148.         {   for (i = 0; i <= SPECIES; i++)
  1149.             {   if (creatureinfo[i].freq == 0)
  1150.                 {   continue;
  1151.                 }
  1152.                 // assert(creatureinfo[i].doublelevel != 0);
  1153.                 if (level >= creatureinfo[i].doublelevel)
  1154.                 {   chance = creatureinfo[i].freq / 2;
  1155.                 } else chance = creatureinfo[i].freq;
  1156.         if (!arand(chance))
  1157.         {   switch(creatureinfo[i].symbol)
  1158.                     {
  1159.                     case BIRD:
  1160.                         if (findempty(&x, &y, creatureinfo[i].wall))
  1161.                         {   // check whether this location is far enough away from the worms
  1162.                             ok = TRUE;
  1163.                             for (j = 0; j <= 3; j++)
  1164.                             {   if
  1165.                                 (   worm[j].lives
  1166.                                  && abs(worm[j].x - x) < DISTANCE_BIRD * 2
  1167.                                  && abs(worm[j].y - y) < DISTANCE_BIRD * 2
  1168.                                 )
  1169.                                 {   ok = FALSE;
  1170.                                     break;
  1171.                             }   }
  1172.                             if (ok)
  1173.                             {   for (j = 0; j <= CREATURES; j++)
  1174.                                 {   if (!creature[j].alive)
  1175.                                     {   createcreature(BIRD, j, x, y, 0, 0, 255, 0);
  1176.                                         break;
  1177.                         }   }   }   }
  1178.                     break;
  1179.                     case CLOUD:
  1180.                         do
  1181.                         {   x = arand(fieldx - 10) + 5;
  1182.                             y = arand(fieldy / 2);
  1183.                             c = field[x][y];
  1184.                         } while (c < FIRSTEMPTY || c > LASTEMPTY);
  1185.                         for (j = 0; j <= CREATURES; j++)
  1186.                         {   if (!creature[j].alive)
  1187.                             {   if (x < fieldx / 2)
  1188.                                 {   createcreature(CLOUD, j, x, y, -1, 0, 255, 0);
  1189.                                 } else
  1190.                                 {   createcreature(CLOUD, j, x, y,  1, 0, 255, 0);
  1191.                                 }
  1192.                                 break;
  1193.                         }   }
  1194.                     break;
  1195.                     case RABBIT:
  1196.                         if (!arand(1))
  1197.                         {   x = 0;
  1198.                             xx = 1;
  1199.                         } else
  1200.                         {   x = fieldx;
  1201.                             xx = -1;
  1202.                         }
  1203.                         y = arand(fieldy);
  1204.                         done = FALSE;
  1205.                         do
  1206.                         {   if (!valid(x, y))
  1207.                             {   done = TRUE;
  1208.                             } elif
  1209.                             (   field[x][y] <= LASTOBJECT
  1210.                              || (field[x][y] >= FIRSTEMPTY && field[x][y] <= LASTEMPTY)
  1211.                             )
  1212.                             {   for (j = 0; j <= CREATURES; j++)
  1213.                                 {   if (!creature[j].alive)
  1214.                                     {   createcreature(RABBIT, j, x, y, xx, 0, 255, 0);
  1215.                                         break;
  1216.                                 }   }
  1217.                                 done = TRUE;
  1218.                             } else
  1219.                             {   x += xx;
  1220.                         }   }
  1221.                         while (!done);
  1222.                     break;
  1223.                     default:
  1224.                         if (findempty(&x, &y, creatureinfo[i].wall))
  1225.                         {   for (j = 0; j <= CREATURES; j++)
  1226.                             {   if (!creature[j].alive)
  1227.                                 {   createcreature(creatureinfo[i].symbol, j, x, y, 0, 0, 255, 0);
  1228.                                     break;
  1229.                         }   }   }
  1230.                     break;
  1231.                     } // end switch
  1232.                 } // end if
  1233.             } // end for
  1234.  
  1235.             /* create slime */
  1236.             if (!arand(FREQ_SLIME) && findempty(&x, &y, FALSE))
  1237.                 change(x, y, SLIME);
  1238.             /* grow slime */
  1239.             if (!arand(FREQ_SLIMEGROW))
  1240.             {   for (x = 0; x <= fieldx; x++)
  1241.                 {   for (y = 0; y <= fieldy; y++)
  1242.                     {   if (field[x][y] == SLIME)
  1243.                         {   for (xx = x - 1; xx <= x + 1; xx++)
  1244.                             {   for (yy = y - 1; yy <= y + 1; yy++)
  1245.                                 {   if (valid(xx, yy) && field[xx][yy] == EMPTY && !arand(1))
  1246.                                     {   field[xx][yy] = TEMPSLIME;
  1247.                 }   }   }   }   }   }
  1248.                 for (x = 0; x <= fieldx; x++)
  1249.                 {   for (y = 0; y <= fieldy; y++)
  1250.                     {   if (field[x][y] == TEMPSLIME)
  1251.                         {   change(x, y, SLIME);
  1252.         }   }   }   }   }
  1253.  
  1254.         /* create objects */
  1255.         for (which = 0; which <= LASTOBJECT; which++)
  1256.         {   if (level || which == TREASURE)
  1257.             {   if (!arand(object[which].freq) && findempty(&x, &y, FALSE))
  1258.                 {   change(x, y, which);
  1259.             }   }
  1260.             elif
  1261.             (   which != TREASURE
  1262.              && which != UMBRELLA
  1263.              && (!arand(object[which].freq / 5))
  1264.              && findempty(&x, &y, FALSE)
  1265.             )
  1266.             {   change(x, y, which);
  1267.         }   }
  1268.  
  1269.         /* create teleports */
  1270.         if
  1271.         (  !arand(FREQ_TELEPORT)
  1272.          && !teleports
  1273.          && findempty(&(teleport[0].x), &(teleport[0].y), FALSE)
  1274.          && findempty(&(teleport[1].x), &(teleport[1].y), FALSE)
  1275.          && (teleport[0].x != teleport[1].x || teleport[0].y != teleport[1].y)
  1276.         )
  1277.         {   teleports = TRUE;
  1278.             change(teleport[0].x, teleport[0].y, TELEPORT);
  1279.             change(teleport[1].x, teleport[1].y, TELEPORT);
  1280. }   }   }
  1281.  
  1282. AGLOBAL SBYTE speedup(SBYTE speed, FLAG isworm)
  1283. {   if (speed == 0)
  1284.     {   speed = SLOW;
  1285.     } elif (speed >= 2)
  1286.     {   speed /= 2;
  1287.     }
  1288.     if (isworm)
  1289.     {   if (speed < FAST)
  1290.         {   speed = FAST;
  1291.     }   }
  1292.  
  1293.     return(speed);
  1294. }
  1295.  
  1296. AGLOBAL void squareblast(SBYTE type, SBYTE player, UBYTE c, SBYTE x, SBYTE y, ABOOL cutter, FLAG superbomb)
  1297. {   SBYTE which;
  1298.     UBYTE filler;
  1299.  
  1300.     if (superbomb)
  1301.     {   // assert(!cutter);
  1302.         filler = DYNAMITE;
  1303.     } else filler = EMPTY;
  1304.  
  1305.     if (c <= LASTOBJECT)
  1306.     {   if (!cutter)
  1307.         {   change(x, y, filler);
  1308.     }   }
  1309.     elif
  1310.     (   (c >= FIRSTTAIL && c <= LASTTAIL)
  1311.      ||  c == WOOD
  1312.      ||  c == SLIME
  1313.      || (superbomb && c >= FIRSTGLOW && c <= LASTGLOW)
  1314.     )
  1315.     {   change(x, y, filler);
  1316.     } elif (c >= FIRSTHEAD && c <= LASTHEAD)
  1317.     {   if (!cutter && (type != HEAD || player != c - FIRSTHEAD))
  1318.         {   if (worm[c - FIRSTHEAD].armour == 0)
  1319.             {   if (superbomb)
  1320.                 {   worm[c - FIRSTHEAD].cause = SUPERBOMB;
  1321.                 } else
  1322.                 {   worm[c - FIRSTHEAD].cause = MINIBOMB;
  1323.                 }
  1324.                 worm[c - FIRSTHEAD].alive = FALSE;
  1325.             } else
  1326.             {   effect(FXUSE_ARMOUR);
  1327.     }   }   }
  1328.     elif (c == MISSILE_C)
  1329.     {   which = whichcreature(x, y, MISSILE_C, 255);
  1330.         if (!cutter)
  1331.         {   if (type == HEAD)
  1332.             {   if (player != c - FIRSTMISSILE)
  1333.                 {   wormkillcreature(player, which);
  1334.                     change(x, y, filler);
  1335.         }   }   }
  1336.         else
  1337.         {   creature[which].alive = FALSE;
  1338.             change(x, y, filler);
  1339.     }    }
  1340.     elif (c >= FIRSTCREATURE && !cutter)
  1341.     {   which = whichcreature(x, y, c, 255);
  1342.         if (creature[which].player != player)
  1343.         {   if (type == HEAD)
  1344.             {   wormkillcreature(player, which);
  1345.                 change(x, y, FIRSTFLOWER + player);
  1346.             } else
  1347.             {   creature[which].alive = FALSE;
  1348.                 change(x, y, filler);
  1349. }   }   }   }
  1350.  
  1351. void timeloop(void)
  1352. {   AUTO    UBYTE i, players = 0;
  1353.     AUTO    SBYTE x, y;
  1354.     PERSIST ABOOL expired = FALSE;
  1355.  
  1356.     secondsleft = atleast(secondsleft, 0);
  1357.     timedisplay[0] = 48 +  (secondsleft / 60);
  1358.     timedisplay[1] = ':';
  1359.     timedisplay[2] = 48 + ((secondsleft % 60) / 10);
  1360.     timedisplay[3] = 48 + ((secondsleft % 60) % 10);
  1361.     timedisplay[4] = 0;
  1362.  
  1363.     if (!level)
  1364.     {   say(timedisplay, worm[treasurer].colour);
  1365.         if (!secondsleft)
  1366.         {   level = reallevel + 1;
  1367.             secondsleft = SECONDSPERLEVEL;
  1368.             newlevel(treasurer);
  1369.     }   }
  1370.     elif (!secondsleft)
  1371.     {   if (!expired)
  1372.         {   effect(FXSIREN);
  1373.             say("Time expired!", WHITE);
  1374.             expired = TRUE;
  1375.  
  1376.             for (i = 0; i <= 3; i++)
  1377.             {   if (worm[i].control != NONE)
  1378.                 {   players++;
  1379.             }   }
  1380.  
  1381.             // assert(players >= 1 && players <= 4);
  1382.             for (i = 1; i <= players; i++)
  1383.             {   do
  1384.                 {   x = (arand(fieldx - 10)) + 5; // not too close to x-edges
  1385.                     y = arand(fieldy);
  1386.                 } while (field[x][y] < FIRSTEMPTY || field[x][y] > LASTEMPTY); // theoretical chance of infinite loop here
  1387.                 change(x, y, START);
  1388.             }
  1389.  
  1390.             // create otters
  1391.             for (i = 0; i <= CREATURES; i++)
  1392.             {   if (!creature[i].alive)
  1393.                 {   for (y = 0; y <= fieldy - 1; y++)
  1394.                     {   if (field[0][y] >= FIRSTEMPTY && field[0][y] <= LASTEMPTY)
  1395.                         {   createcreature(OTTER, i, 0,      y, 0,  1, 255, 0);
  1396.                             break;
  1397.                     }   }
  1398.                     break;
  1399.             }   }
  1400.             for (i = 0; i <= CREATURES; i++)
  1401.             {   if (!creature[i].alive)
  1402.                 {   for (y = fieldy; y >= 1; y--)
  1403.                     {   if (field[fieldx][y] >= FIRSTEMPTY && field[fieldx][y] <= LASTEMPTY)
  1404.                         {   createcreature(OTTER, i, fieldx, y, 0, -1, 255, 0);
  1405.                             break;
  1406.                     }   }
  1407.                     break;
  1408.     }   }   }   }
  1409.     else
  1410.     {   if (secondsleft <= 5)
  1411.         {   effect(FXSIREN);
  1412.         }
  1413.         expired = FALSE;
  1414.         say(timedisplay, WHITE);
  1415. }   }
  1416.  
  1417. void train(SCANCODE scancode, FLAG shift)
  1418. {   SBYTE x, y;
  1419.     UBYTE i;
  1420.  
  1421.     switch(scancode)
  1422.     {
  1423.     case HELP:
  1424.         trainer = ~trainer;
  1425.     break;
  1426.     case NUMERICSLASH:
  1427.         /* Complete the level. */
  1428.         if (trainer)
  1429.         {   trainer = FALSE;
  1430.             endoflevel();
  1431.         }
  1432.     break;
  1433.     case NUMERICASTERISK:
  1434.         /* field[][] dump, for debugging purposes. */
  1435.         if (trainer)
  1436.         {   trainer = FALSE;
  1437.             say("Xenia rules!", PURPLE);
  1438.             for (x = 0; x <= fieldx; x++)
  1439.                 for (y = 0; y <= fieldy; y++)
  1440.                     draw(x, y, field[x][y]);
  1441.             anykey(FALSE);
  1442.         }
  1443.     break;
  1444.     case NUMERICMINUS:
  1445.         if (trainer)
  1446.         {   trainer = FALSE;
  1447.             say("Tiyla rules!", PURPLE);
  1448.             for (i = 0; i <= ARRAYSIZE; i++)
  1449.             {   draw(fieldx - 15 + (i % 16), i / 16, i);
  1450.             }
  1451.             if (shift)
  1452.             {   for (i = 0; i <= TAILARRAYSIZE; i++)
  1453.                 {   drawtail(fieldx - 27 + (i % 28), (i / 28) + 16, i);
  1454.             }   }
  1455.             else
  1456.             {   for (i = 0; i <= TAILARRAYSIZE; i++)
  1457.                 {   drawtail(fieldx - 15 + (i % 16), (i / 16) + 16, i);
  1458.             }   }
  1459.             for (i = 0; i <= HEADARRAYSIZE; i++)
  1460.             {   realdrawhead(fieldx - 15 + (i % 16), (i / 16) + 32, i);
  1461.             }
  1462.             anykey(FALSE);
  1463.         }
  1464.     break;
  1465.     case NUMERICPLUS:
  1466.         if (trainer)
  1467.         {   trainer = FALSE;
  1468.             if (worm[1].lives)
  1469.             {   say("Trainer activated!", PURPLE);
  1470.                 anykey(FALSE);
  1471.  
  1472.                 worm[1].lives = LIVESLIMIT;
  1473.                 stat(1, MINIHEALER);
  1474.                 worm[1].ammo = AMMOLIMIT;
  1475.                 stat(1, AMMO);
  1476.                 worm[1].power = POWERLIMIT;
  1477.                 stat(1, POWER);
  1478.                 worm[1].brakes = TRUE;
  1479.                 stat(1, BRAKES);
  1480.  
  1481.                 worm[1].affixer  = TRUE;
  1482.                 worm[1].remnants = TRUE;
  1483.                 worm[1].sideshot = TRUE;
  1484.                 worm[1].pusher   = TRUE;
  1485.                 worm[1].encloser = TRUE;
  1486.                 worm[1].autojump = TRUE;
  1487.  
  1488.                 worm[1].armour   = ARMOURLIMIT;
  1489.                 worm[1].glow     = GLOWLIMIT;
  1490.                 worm[1].cutter   = CUTTERLIMIT;
  1491.  
  1492.                 for (i = 0; i <= LASTOBJECT; i++)
  1493.                 {   icon(1, i);
  1494.                 }
  1495.  
  1496.                 trainer = FALSE;
  1497.         }   }
  1498.     break;
  1499.     default:
  1500.     break;
  1501. }   }
  1502.  
  1503. AGLOBAL void turnworm(SBYTE player, SBYTE deltax, SBYTE deltay)
  1504. {   if (worm[player].deltax == deltax && worm[player].deltay == deltay)
  1505.     {   worm[player].speed = speedup(worm[player].speed, TRUE);
  1506.         stat(player, BRAKES);
  1507.     } elif (worm[player].deltax == -deltax && worm[player].deltay == -deltay)
  1508.     {   worm[player].speed = slowdown(worm[player].speed, TRUE, worm[player].brakes);
  1509.         stat(player, BRAKES);
  1510.     } else
  1511.     {   worm[player].deltax = deltax;
  1512.         worm[player].deltay = deltay;
  1513. }   }
  1514.  
  1515. SBYTE valid(SBYTE x, SBYTE y)
  1516. {   if (x < 0 || y < 0)
  1517.     {   return(FALSE);
  1518.     } elif (a == FIELDEDIT)
  1519.     {   if (x > MINFIELDX || y > MINFIELDY)
  1520.         {   return(FALSE);
  1521.         } else return(TRUE);
  1522.     } else
  1523.     {   // assert(a != FIELDEDIT);
  1524.         if (x > fieldx || y > fieldy)
  1525.         {   return(FALSE);
  1526.         } else return(TRUE);
  1527. }   }
  1528.  
  1529. AGLOBAL void wormscore(SBYTE player, SLONG score)
  1530. {   worm[player].score += score * worm[player].multi * players;
  1531.     stat(player, BONUS);
  1532. }
  1533.  
  1534. SBYTE xwrap(SBYTE x)
  1535. {   if (x < 0)
  1536.         x += fieldx + 1;
  1537.     elif (x > fieldx)
  1538.         x -= fieldx + 1;
  1539.     return(x);
  1540. }
  1541. SBYTE ywrap(SBYTE y)
  1542. {   if (y < 0)
  1543.         y += fieldy + 1;
  1544.     elif (y > fieldy)
  1545.         y -= fieldy + 1;
  1546.     return(y);
  1547. }
  1548.  
  1549. MODULE void ramming(SBYTE player)
  1550. {   SBYTE i;
  1551.  
  1552.     worm[player].rammed = TRUE;
  1553.     worm[player].x = xwrap(worm[player].x - worm[player].deltax);
  1554.     worm[player].y = ywrap(worm[player].y - worm[player].deltay);
  1555.     for (i = 0; i <= PROTECTORS; i++)
  1556.     {   /* no point checking whether the protectors are alive or dead */
  1557.         protector[player][i].x -= worm[player].deltax;
  1558.         protector[player][i].y -= worm[player].deltay;
  1559. }   }
  1560.  
  1561. MODULE SWORD atleast(SWORD value, SWORD minimum)
  1562. {   if (value < minimum)
  1563.         return(minimum);
  1564.     else return(value);
  1565. }
  1566.  
  1567. AGLOBAL void __inline change(SBYTE x, SBYTE y, UBYTE image)
  1568. {   // assert(valid(x, y));
  1569.     field[x][y] = image;
  1570.     draw(x, y, image);
  1571. }
  1572.  
  1573. /* WormWars FSET format for fieldset contents and high score table (Amiga
  1574. and IBM-PC), as follows:
  1575.  
  1576. header
  1577.         TEXT[]                          "FSET x.x" (NULL-terminated)
  1578.     SBYTE                levels;
  1579. high score table
  1580.     for (slot = 0; slot <= HISCORES; slot++)
  1581.     {    SBYTE            hiscore[slot].player,
  1582.                     hiscore[slot].level;
  1583.         SLONG            hiscore[slot].score;
  1584.         TEXT[]            hiscore[slot].name (NULL-terminated)
  1585.         TEXT[]            hiscore[slot].time (NULL-terminated)
  1586.         TEXT[]            hiscore[slot].date (NULL-terminated)
  1587.     }
  1588. level data
  1589.     for (level = 0; level <= levels; level++)
  1590.     {    SBYTE            startx[level],
  1591.                                         starty[level];
  1592.                 UBYTE                   reserved[6];
  1593.                 for (x = 0; x <= MINFIELDX; x++)
  1594.                         for (y = 0; y <= MINFIELDY; y++)
  1595.                 SBYTE    board[level][x][y];
  1596.     }
  1597. version string
  1598.         TEXT[]                          "$VER: Worm Wars x.x (dd.mm.yy) $" (NULL-terminated) */
  1599.  
  1600. MODULE void wormworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  1601. {   if (worm[which1].armour == 0 && worm[which2].armour == 0)
  1602.     {   /* both worms die */
  1603.         worm[which1].cause  = FIRSTHEAD + which2;
  1604.         worm[which1].alive  = FALSE;
  1605.         worm[which2].cause  = FIRSTHEAD + which1;
  1606.         worm[which2].alive  = FALSE;
  1607.     } elif (worm[which1].armour > 0 && worm[which2].armour == 0)
  1608.     {   /* 1st worm lives, 2nd worm dies  */
  1609.         worm[which2].cause  = FIRSTHEAD + which1;
  1610.         worm[which2].alive  = FALSE;
  1611.     } elif (worm[which1].armour == 0 && worm[which2].armour > 0)
  1612.     {   /* 1st worm dies, 2nd worm lives */
  1613.         worm[which1].cause  = FIRSTHEAD + which2;
  1614.         worm[which1].alive  = FALSE;
  1615. }   }
  1616. AGLOBAL void protworm(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  1617. {   SBYTE i, j = -1; // to prevent spurious warnings
  1618.  
  1619.     for (i = 0; i <= PROTECTORS; i++)
  1620.          if (protector[which1][i].alive && protector[which1][i].x == x && protector[which1][i].y == y)
  1621.          {    j = i;
  1622.               break;
  1623.          }
  1624.  
  1625.     if (which1 != which2)
  1626.     {   if (worm[which2].armour == 0)
  1627.         {   effect(FXBORN_PROTECTOR);
  1628.             worm[which2].cause  = FIRSTPROTECTOR + which1;
  1629.             worm[which2].alive  = FALSE;
  1630.         } else
  1631.         {   effect(FXUSE_ARMOUR);
  1632.             protector[which1][j].visible = FALSE;
  1633.     }   }
  1634.     else
  1635.     {   /* protector is over worm's own head; caused by ramming */
  1636.         protector[which1][j].visible = FALSE;
  1637. }   }
  1638. AGLOBAL void protprot(SBYTE x, SBYTE y, UBYTE which1, UBYTE which2)
  1639. {   SBYTE i, p1 = -1, p2 = -1; // to prevent spurious warnings
  1640.  
  1641.     /* Find both protectors */
  1642.  
  1643.     for (i = 0; i <= PROTECTORS; i++)
  1644.     {   if (protector[which1][i].alive && protector[which1][i].x == x && protector[which1][i].y == y)
  1645.             p1 = i;
  1646.         if (protector[which2][i].alive && protector[which2][i].x == x && protector[which2][i].y == y)
  1647.             p2 = i;
  1648.     }
  1649.     protector[which1][p1].alive = FALSE;
  1650.     protector[which2][p2].alive = FALSE;
  1651.     change(x, y, EMPTY);
  1652. }
  1653.  
  1654. void icon(SBYTE player, UBYTE image)
  1655. {   SBYTE x = -4, y = (player * 10) + 6;
  1656.  
  1657.     switch(image)
  1658.     {
  1659.     // booleans
  1660.     case AFFIXER:
  1661.         if (worm[player].affixer)
  1662.             draw(x, y, AFFIXER);
  1663.         else draw(x, y, BLACKENED);
  1664.     break;
  1665.     case AUTOJUMP:
  1666.         if (worm[player].autojump)
  1667.             draw(x + 1, y, AUTOJUMP);
  1668.         else draw(x + 1, y, BLACKENED);
  1669.     break;
  1670.     case ENCLOSER:
  1671.         if (worm[player].encloser)
  1672.             draw(x + 2, y, ENCLOSER);
  1673.         else draw(x + 2, y, BLACKENED);
  1674.     break;
  1675.     case PUSHER:
  1676.         if (worm[player].pusher)
  1677.             draw(x, y + 1, PUSHER);
  1678.         else draw(x, y + 1, BLACKENED);
  1679.     break;
  1680.     case REMNANTS:
  1681.         if (worm[player].remnants)
  1682.             draw(x + 1, y + 1, REMNANTS);
  1683.         else draw(x + 1, y + 1, BLACKENED);
  1684.     break;
  1685.     case SIDESHOT:
  1686.         if (worm[player].sideshot)
  1687.             draw(x + 2, y + 1, SIDESHOT);
  1688.         else draw(x + 2, y + 1, BLACKENED);
  1689.     break;
  1690.     case ARMOUR:
  1691.         if (worm[player].armour)
  1692.         {   if (worm[player].armour < 10)
  1693.             {   if ((r % 4) <= 1)
  1694.                 {   draw(x, y + 2, ARMOUR);
  1695.                 } else draw(x, y + 2, BLACKENED);
  1696.             } else draw(x, y + 2, ARMOUR);
  1697.         } else draw(x, y + 2, BLACKENED);
  1698.     break;
  1699.     case CUTTER:
  1700.         if (worm[player].cutter)
  1701.         {   if (worm[player].cutter < 10)
  1702.             {   if ((r % 4) <= 1)
  1703.                 {   draw(x + 1, y + 2, CUTTER);
  1704.                 } else draw(x + 1, y + 2, BLACKENED);
  1705.             } else draw(x + 1, y + 2, CUTTER);
  1706.         } else draw(x + 1, y + 2, BLACKENED);
  1707.     break;
  1708.     case GLOW:
  1709.         if (worm[player].glow)
  1710.         {   if (worm[player].glow < 10)
  1711.             {   if ((r % 4) <= 1)
  1712.                 {   draw(x + 2, y + 2, GLOW);
  1713.                 } else draw(x + 2, y + 2, BLACKENED);
  1714.             } else draw(x + 2, y + 2, GLOW);
  1715.         } else draw(x + 2, y + 2, BLACKENED);
  1716.     break;
  1717.     default:
  1718.     break;
  1719. }   }
  1720.  
  1721. AGLOBAL void drawsquare(SBYTE x, SBYTE y)
  1722. {   if (field[x][y] >= FIRSTCREATURE)
  1723.     {   drawcreature(whichcreature(x, y, field[x][y], 255));
  1724.     } elif (field[x][y] >= FIRSTHEAD && field[x][y] <= LASTHEAD)
  1725.     {   drawhead(field[x][y] - FIRSTHEAD);
  1726.     } elif (field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL)
  1727.     {   drawtail(x, y, tailfield[x][y] + (SECONDMAGIC * (field[x][y] - FIRSTTAIL)));
  1728.     } elif (field[x][y] >= FIRSTGLOW && field[x][y] <= LASTGLOW)
  1729.     {   drawtail(x, y, tailfield[x][y] + (SECONDMAGIC * (field[x][y] - FIRSTGLOW)));
  1730.     } else
  1731.     {   draw(x, y, field[x][y]);
  1732. }   }
  1733.  
  1734. AGLOBAL void updatearrow(SBYTE arrowy)
  1735. {   SBYTE i, var = -1;
  1736.  
  1737.     /* var of:
  1738.                   -2         : many there
  1739.                   -1         : nothing there
  1740.                  0-3         : just that worm,
  1741.        FIRSTNUMBER-LASTNUMBER: just that number */
  1742.  
  1743.     for (i = 0; i <= 3; i++)
  1744.     {   if
  1745.         (    worm[i].control != NONE
  1746.          &&  worm[i].y == arrowy
  1747.          && (worm[i].lives || field[worm[i].x][worm[i].y] == i - FIRSTGRAVE)
  1748.         )
  1749.         {   if (var == -1)
  1750.             {   var = i;
  1751.             } else var = -2;
  1752.     }   }
  1753.     if (numbery == arrowy)
  1754.         if (var == -1)
  1755.             var = FIRSTNUMBER + number - 1;
  1756.         else var = -2;
  1757.     if (var == -2)
  1758.         draw(ARROWX, arrowy, ALL);
  1759.     elif (var == -1 || var == LASTNUMBER + 1) // var may equal LASTNUMBER + 1 at end of level
  1760.         draw(ARROWX, arrowy, BLACKARROW);
  1761.     elif (var >= FIRSTNUMBER && var <= LASTNUMBER)
  1762.         draw(ARROWX, arrowy, var);
  1763.     else
  1764.     {   // assert(var >= 0 && var <= 3);
  1765.         if (worm[var].lives)
  1766.             draw(ARROWX, arrowy, FIRSTARROW + var);
  1767.         else draw(ARROWX, arrowy, FIRSTGRAVE + var);
  1768. }   }
  1769.  
  1770. AGLOBAL void __inline bangdynamite(SBYTE x, SBYTE y, SBYTE player)
  1771. {   SBYTE xx, yy;
  1772.  
  1773.     // Infects (turns to bang-dynamite) all surrounding dynamite.
  1774.  
  1775.     for (xx = x - 1; xx <= x + 1; xx++)
  1776.     {   for (yy = y - 1; yy <= y + 1; yy++)
  1777.         {   if (valid(xx, yy))
  1778.             {   if (field[xx][yy] == DYNAMITE)
  1779.                 {   field[xx][yy] = TEMPBANGDYNAMITE;
  1780.                     infector[xx][yy] = player;
  1781. }   }   }   }   }
  1782.  
  1783. AGLOBAL ULONG arand(ULONG number)
  1784. {   ULONG result;
  1785.  
  1786.     result = (ULONG) (rand() % (number + 1));
  1787.     return(result);
  1788. }
  1789.  
  1790. /* NAME     align -- right-justify a string within another string
  1791. SYNOPSIS    align(STRPTR, SBYTE, TEXT);
  1792. FUNCTION    Moves all text in a string to the right, padding with
  1793.             spaces. Does not itself add a null terminator.
  1794. INPUTS      string - pointer to the string of text
  1795.               size - size in characters of the containing string
  1796.             filler - what to pad the left of the string with
  1797. NOTE        Null terminators are written over by this function, but that
  1798.             does not matter, because calling functions use Text() with an
  1799.             explicit length. This function only works with monospaced
  1800.             fonts. */
  1801.  
  1802. AGLOBAL void align(STRPTR string, SBYTE size, TEXT filler)
  1803. {   SBYTE i, shift, length;
  1804.  
  1805.     length = strlen((const char*) string);
  1806.     shift = size - length;
  1807.     for (i = 1; i <= length; i++)
  1808.         *(string + size - i) = *(string + size - i - shift);
  1809.     for (i = 0; i <= shift - 1; i++)
  1810.         *(string + i) = filler;
  1811. }
  1812.  
  1813. MODULE void ReadGameports(void)
  1814. {   ReadStandardJoystick(0);
  1815.     ReadStandardJoystick(1);
  1816.     ReadAdapterJoystick(2);
  1817.     ReadAdapterJoystick(3);
  1818.     ReadGamepads();
  1819. }
  1820.  
  1821. AGLOBAL void checkrectangle(SBYTE direction, SBYTE player, SBYTE horizontalsize, SBYTE verticalsize)
  1822. {   AUTO SBYTE i, x, y, leftx, rightx, topy, bottomy;
  1823.     AUTO UBYTE c;
  1824.     PERSIST struct
  1825.     {   SBYTE deltax[4], deltay[4];
  1826.     } deltas[4] =
  1827.     { { { 0, -1,  0,  1}, // northwest
  1828.         {-1,  0,  1,  0}
  1829.       },
  1830.       { { 0,  1,  0, -1}, // northeast
  1831.         {-1,  0,  1,  0}
  1832.       },
  1833.       { { 0,  1,  0, -1}, // southeast
  1834.         { 1,  0, -1,  0}
  1835.       },
  1836.       { { 0, -1,  0,  1}, // southwest
  1837.         { 1,  0, -1,  0}
  1838.     } };
  1839.     PERSIST struct
  1840.     {   SBYTE leftx, rightx, topy, bottomy;
  1841.     } enclose[4] =
  1842.     { {-127,   -1, -127,  -1 }, // northwest
  1843.       {   1,  127, -127,  -1 }, // northeast
  1844.       {   1,  127,    1, 127 }, // southeast
  1845.       {-127,   -1,    1, 127 }  // southwest
  1846.     };
  1847.  
  1848.     x = worm[player].x;
  1849.     y = worm[player].y; // for speed
  1850.  
  1851.     for (i = 0; i <= verticalsize; i++)
  1852.     {   x += deltas[direction].deltax[0];
  1853.         y += deltas[direction].deltay[0];
  1854.         if
  1855.         (   (!valid(x, y))
  1856.          || (   field[x][y] != FIRSTTAIL + player
  1857.              && field[x][y] != FIRSTGLOW + player
  1858.         )   )
  1859.         {   return;
  1860.     }   }
  1861.     for (i = 0; i <= horizontalsize; i++)
  1862.     {   x += deltas[direction].deltax[1];
  1863.         y += deltas[direction].deltay[1];
  1864.         if
  1865.         (   (!valid(x, y))
  1866.          || (   field[x][y] != FIRSTTAIL + player
  1867.              && field[x][y] != FIRSTGLOW + player
  1868.         )   )
  1869.         {   return;
  1870.     }   }
  1871.     for (i = 0; i <= verticalsize; i++)
  1872.     {   x += deltas[direction].deltax[2];
  1873.         y += deltas[direction].deltay[2];
  1874.         if
  1875.         (   (!valid(x, y))
  1876.          || (   field[x][y] != FIRSTTAIL + player
  1877.              && field[x][y] != FIRSTGLOW + player
  1878.         )   )
  1879.         {   return;
  1880.     }   }
  1881.     for (i = 0; i <= horizontalsize - 1; i++)
  1882.     {   x += deltas[direction].deltax[3];
  1883.         y += deltas[direction].deltay[3];
  1884.         if
  1885.         (   (!valid(x, y))
  1886.          || (   field[x][y] != FIRSTTAIL + player
  1887.              && field[x][y] != FIRSTGLOW + player
  1888.         )   )
  1889.         {   return;
  1890.     }   }
  1891.  
  1892.     if (enclose[direction].leftx < -1)
  1893.         enclose[direction].leftx = -horizontalsize;
  1894.     elif (enclose[direction].leftx > 1)
  1895.         enclose[direction].leftx = horizontalsize + 1;
  1896.     if (enclose[direction].rightx < -1)
  1897.         enclose[direction].rightx = -(horizontalsize + 1);
  1898.     elif (enclose[direction].rightx > 1)
  1899.         enclose[direction].rightx = horizontalsize;
  1900.     if (enclose[direction].topy < -1)
  1901.         enclose[direction].topy = -verticalsize;
  1902.     elif (enclose[direction].topy > 1)
  1903.         enclose[direction].topy = verticalsize + 1;
  1904.     if (enclose[direction].bottomy < -1)
  1905.         enclose[direction].bottomy = -(verticalsize + 1);
  1906.     elif (enclose[direction].bottomy > 1)
  1907.         enclose[direction].bottomy = verticalsize;
  1908.  
  1909.       leftx = worm[player].x + enclose[direction].leftx;
  1910.      rightx = worm[player].x + enclose[direction].rightx;
  1911.        topy = worm[player].y + enclose[direction].topy;
  1912.     bottomy = worm[player].y + enclose[direction].bottomy;
  1913.     // assert(leftx >= 0 && rightx <= fieldx && topy >= 0 && bottomy <= fieldy && leftx < rightx && topy < bottomy);
  1914.  
  1915.     for (x = leftx; x <= rightx; x++)
  1916.     {   for (y = topy; y <= bottomy; y++)
  1917.         {   c = field[x][y];
  1918.             if
  1919.             (    (c >= FIRSTEMPTY && c <= LASTEMPTY)
  1920.              || ((c >= FIRSTTAIL  && c <= LASTTAIL ) && c != FIRSTTAIL + player)
  1921.              || ((c >= FIRSTGLOW  && c <= LASTGLOW ) && c != FIRSTGLOW + player)
  1922.             )
  1923.             {   change(x, y, FIRSTGLOW + player);
  1924.                 enclosed = TRUE;
  1925.             } elif (c >= FIRSTCREATURE)
  1926.             {   wormkillcreature(player, whichcreature(x, y, c, 255));
  1927.                 change(x, y, FIRSTFLOWER + player);
  1928.                 enclosed = TRUE;
  1929.     }   }   }
  1930.     if (enclosed)
  1931.     {   effect(FXDO_ENCLOSE);
  1932. }   }
  1933.  
  1934. MODULE void endoflevel(void)
  1935. {   SBYTE advancer,
  1936.           player;
  1937.     UWORD counter[4] = {0, 0, 0, 0};
  1938.     SBYTE x, y;
  1939.  
  1940.         for (player = 0; player <= 3; player++)
  1941.         {   if (worm[player].lives)
  1942.             {   for (x = 0; x <= fieldx; x++)
  1943.                 {   for (y = 0; y <= fieldy; y++)
  1944.                     {   if (field[x][y] == FIRSTTAIL + player || field[x][y] == FIRSTGLOW + player)
  1945.                         {   counter[player]++;
  1946.         }   }   }   }   }
  1947.         if (counter[0] >= counter[1]
  1948.          && counter[0] >= counter[2]
  1949.          && counter[0] >= counter[3])
  1950.         {   advancer = 0;
  1951.         } elif (counter[1] >= counter[0]
  1952.          && counter[1] >= counter[2]
  1953.          && counter[1] >= counter[3])
  1954.         {   advancer = 1;
  1955.         } elif (counter[2] >= counter[0]
  1956.          && counter[2] >= counter[1]
  1957.          && counter[2] >= counter[3])
  1958.         {   advancer = 2;
  1959.         } else
  1960.         {   advancer = 3;
  1961.         }
  1962.  
  1963.     if (level++ == 0)
  1964.     {   level = reallevel + 1;
  1965.         reallevel = 0;
  1966.     }
  1967.     stopfx();
  1968.     newlevel(advancer);
  1969. }
  1970.  
  1971. AGLOBAL FLAG getnumber(SBYTE player)
  1972. {   FLAG  done;
  1973.     SBYTE x, y;
  1974.  
  1975.     /* This function returns TRUE if the final number (ie. 9) was gotten,
  1976.     otherwise FALSE.
  1977.  
  1978.     The calling function is responsible for calling putnumber() if it
  1979.     wants a new number to appear. */
  1980.  
  1981.     effect(FXDING);
  1982.     wormscore(player, POINTS_LETTER * number);
  1983.     worm[player].numbers++;
  1984.     number++;
  1985.  
  1986.     if (number == 10)
  1987.     {   endoflevel();
  1988.         return(TRUE);
  1989.     } // else
  1990.     do
  1991.     {   done = findempty(&x, &y, FALSE);
  1992.     } while (!done);
  1993.     change(x, y, FIRSTCHERRY + player);
  1994.     return(FALSE);
  1995. }
  1996.  
  1997. AGLOBAL ULONG wormobject(UBYTE player, SBYTE x, SBYTE y)
  1998. {   AUTO    UBYTE c = field[x][y], d;
  1999.     AUTO    ULONG score = object[c].score;
  2000.     AUTO    UBYTE i, j, generated = 0;
  2001.     AUTO    SBYTE xx, xxx, yy, yyy;
  2002.     AUTO    ABOOL done;
  2003.     PERSIST UBYTE otherfield[MAXFIELDX + 1][MAXFIELDY + 1];
  2004.  
  2005.     for (i = 0; i <= MAGNETS; i++)
  2006.         if (magnet[i].alive && x == magnet[i].x && y == magnet[i].y)
  2007.              magnet[i].alive = FALSE;
  2008.  
  2009.     if (!valid(x, y)) // defensive programming
  2010.     {   return 0;
  2011.  
  2012.         /* AUTO TEXT temp1[SAYLIMIT + 1], temp2[8];
  2013.  
  2014.         strcpy(temp1, "BAD OBJECT AT x: ");
  2015.         stci_d(temp2, x);
  2016.         strcat(temp1, temp2);
  2017.         strcat(temp1, ", y: ");
  2018.         stci_d(temp2, y);
  2019.         strcat(temp1, temp2);
  2020.         strcat(temp1, "!");
  2021.         say(temp1, worm[player].colour);
  2022.         draw(fieldx + 1, 0, c); // indicates which object
  2023.         Delay(250);
  2024.         clearkybd();
  2025.         anykey(FALSE); */
  2026.     }
  2027.  
  2028.     switch(c)
  2029.     {
  2030.     case BONUS:
  2031.         if (level != 0)
  2032.         {   getnumber(player);
  2033.             change(numberx, numbery, FIRSTNUMBER + number - 1);
  2034.             updatearrow(numbery);
  2035.         }
  2036.     break;
  2037.     case AMMO:
  2038.         effect(FXGET_AMMO);
  2039.         worm[player].ammo += ADD_AMMO;
  2040.         stat(player, AMMO);
  2041.     break;
  2042.     case ARMOUR:
  2043.         effect(FXGET_OBJECT);
  2044.         worm[player].armour += ADD_ARMOUR + arand(RAND_ARMOUR);
  2045.         if (worm[player].armour > ARMOURLIMIT)
  2046.         {   worm[player].armour = ARMOURLIMIT;
  2047.         }
  2048.         icon(player, ARMOUR);
  2049.     break;
  2050.     case BRAKES:
  2051.         effect(FXGET_OBJECT);
  2052.         worm[player].brakes = TRUE;
  2053.         stat(player, BRAKES);
  2054.     break;
  2055.     case MINIBOMB:
  2056.         drawhead(player);
  2057.         bombblast(HEAD, player, worm[player].x, worm[player].y, FALSE);
  2058.     break;
  2059.     case SUPERBOMB:
  2060.         drawhead(player);
  2061.         bombblast(HEAD, player, worm[player].x, worm[player].y, TRUE);
  2062.     break;
  2063.     case POWER:
  2064.         effect(FXGET_POWERUP);
  2065.         if (worm[player].power < POWERLIMIT)
  2066.         {   worm[player].power += 2;
  2067.             stat(player, POWER);
  2068.         }
  2069.     break;
  2070.     case SLAYER:
  2071.         for (i = 0; i <= CREATURES; i++)
  2072.         {   if (creature[i].alive)
  2073.             {   if (creature[i].player != player)
  2074.                 {   wormkillcreature(player, i);
  2075.                     change(creature[i].x, creature[i].y, EMPTY);
  2076.         }   }   }
  2077.         for (i = 0; i <= 3; i++)
  2078.         {   if (player != i && worm[i].armour == 0)
  2079.             {   worm[i].alive = FALSE;
  2080.                 worm[i].cause = SLAYER;
  2081.         }   }
  2082.         for (x = 0; x <= fieldx; x++)
  2083.             for (y = 0; y <= fieldy; y++)
  2084.                 if (field[x][y] == SLIME)
  2085.                     change(x, y, DYNAMITE);
  2086.     break;
  2087.     case PROTECTOR:
  2088.         // create protector
  2089.         done = FALSE;
  2090.         for (i = 0; i <= PROTECTORS; i++)
  2091.         {   if (!protector[player][i].alive && !done)
  2092.             {   do
  2093.                 {   protector[player][i].relx = (arand(1) * 2) - 1;
  2094.                     protector[player][i].rely = (arand(1) * 2) - 1;
  2095.                     for (j = 0; j <= PROTECTORS; j++)
  2096.                     {   if
  2097.                         (   i == NOSE
  2098.                          || !protector[player][j].alive
  2099.                          ||  protector[player][j].x != xwrap(worm[player].x + protector[player][i].relx)
  2100.                          ||  protector[player][j].y != ywrap(worm[player].y + protector[player][i].rely)
  2101.                         ) // if we can find an area without a preexisting protector
  2102.                         {   effect(FXBORN_PROTECTOR);
  2103.                             done = TRUE;
  2104.                             protector[player][i].alive = TRUE;
  2105.                             protector[player][i].visible = FALSE;
  2106.                             protector[player][i].last = EMPTY;
  2107.                             if (i == NOSE)
  2108.                             {   worm[player].position = -1;
  2109.                 }   }   }   }
  2110.                 while (!done);
  2111.         }   }
  2112.     break;
  2113.     case MISSILE_O:
  2114.         for (i = 0; i <= CREATURES; i++)
  2115.         {   if (!creature[i].alive)
  2116.             {   createcreature(MISSILE_C, i, worm[player].x, worm[player].y, 0, 0, player, 0);
  2117.                 break;
  2118.         }   }
  2119.     break;
  2120.     case MINIHEALER:
  2121.         effect(FXGET_OBJECT);
  2122.         worm[player].lives += ADD_MINIHEALER;
  2123.         stat(player, MINIHEALER);
  2124.     break;
  2125.     case MULTIPLIER:
  2126.         effect(FXGET_OBJECT);
  2127.         if (worm[player].multi < MULTILIMIT)
  2128.             worm[player].multi *= 2;
  2129.     break;
  2130.     case ICE:
  2131.         effect(FXGET_OBJECT);
  2132.         ice += ADD_ICE + arand(RAND_ICE);
  2133.     break;
  2134.     case GROWER:
  2135.         effect(FXGET_GROWER);
  2136.  
  2137.         /* grow dynamite */
  2138.         for (x = 0; x <= fieldx; x++)
  2139.             for (y = 0; y <= fieldy; y++)
  2140.                 if (field[x][y] == DYNAMITE)
  2141.                     for (xx = x - 1; xx <= x + 1; xx++)
  2142.                         for (yy = y - 1; yy <= y + 1; yy++)
  2143.                             if (valid(xx, yy))
  2144.                                 if (field[xx][yy] == EMPTY)
  2145.                                     field[xx][yy] = TEMPDYNAMITE;
  2146.         /* grow silver */
  2147.         for (x = 0; x <= fieldx; x++)
  2148.             for (y = 0; y <= fieldy; y++)
  2149.                 if (field[x][y] == SILVER)
  2150.                     for (xx = x - 1; xx <= x + 1; xx++)
  2151.                         for (yy = y - 1; yy <= y + 1; yy++)
  2152.                             if (valid(xx, yy))
  2153.                                 if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPDYNAMITE)
  2154.                                     field[xx][yy] = TEMPSILVER;
  2155.         /* grow gold */
  2156.         for (x = 0; x <= fieldx; x++)
  2157.             for (y = 0; y <= fieldy; y++)
  2158.                 if (field[x][y] == GOLD)
  2159.                     for (xx = x - 1; xx <= x + 1; xx++)
  2160.                         for (yy = y - 1; yy <= y + 1; yy++)
  2161.                             if (valid(xx, yy))
  2162.                                 if (field[xx][yy] == EMPTY || field[xx][yy] == TEMPDYNAMITE || field[xx][yy] == TEMPSILVER)
  2163.                                     field[xx][yy] = TEMPGOLD;
  2164.         /* update field */
  2165.         for (x = 0; x <= fieldx; x++)
  2166.             for (y = 0; y <= fieldy; y++)
  2167.                 switch (field[x][y])
  2168.                 {
  2169.                 case TEMPGOLD:
  2170.                     change(x, y, GOLD);
  2171.                 break;
  2172.                 case TEMPSILVER:
  2173.                     change(x, y, SILVER);
  2174.                 break;
  2175.                 case TEMPDYNAMITE:
  2176.                     change(x, y, DYNAMITE);
  2177.                 break;
  2178.                 default:
  2179.                 break;
  2180.                 }
  2181.     break;
  2182.     case TREASURE:
  2183.         treasurer = player;
  2184.         if (level)
  2185.         {   secondsperlevel = 0;
  2186.             say("Bonus Level", worm[treasurer].colour);
  2187.         }
  2188.         secondsperlevel += ADD_TREASURE + arand(RAND_TREASURE);
  2189.         if (secondsperlevel > TIMELIMIT)
  2190.         {   secondsperlevel = TIMELIMIT;
  2191.         }
  2192.         if (level)
  2193.         {   stat(player, BONUS);
  2194.             reallevel = level;
  2195.             level = 0;
  2196.             newlevel(player);
  2197.         }
  2198.     break;
  2199.     case AFFIXER:
  2200.         effect(FXGET_OBJECT);
  2201.         worm[player].affixer = TRUE;
  2202.         icon(player, AFFIXER);
  2203.     break;
  2204.     case SWITCHER:
  2205.         effect(FXGET_OBJECT);
  2206.         for (x = 0; x <= fieldx; x++)
  2207.         {   for (y = 0; y <= fieldy; y++)
  2208.             {   if (field[x][y] >= FIRSTTAIL && field[x][y] <= LASTTAIL)
  2209.                 {   if (field[x][y] == FIRSTTAIL + player)
  2210.                     {   field[x][y] = FIRSTGLOW + player;
  2211.                         drawtail(x, y, tailfield[x][y] + (player * SECONDMAGIC) + FIRSTMAGIC);
  2212.                     } else
  2213.                     {   field[x][y] = FIRSTTAIL + player;
  2214.                         drawtail(x, y, tailfield[x][y] + (player * SECONDMAGIC));
  2215.                 }   }
  2216.                 elif (field[x][y] >= FIRSTGLOW && field[x][y] <= LASTGLOW && field[x][y] != FIRSTGLOW + player)
  2217.                 {   field[x][y] = FIRSTGLOW + player;
  2218.                     drawtail(x, y, tailfield[x][y] + (player * SECONDMAGIC));
  2219.                 } elif (field[x][y] == SLIME)
  2220.                 {   change(x, y, DYNAMITE);
  2221.         }   }   }
  2222.     break;
  2223.     case SUPERHEALER:
  2224.         effect(FXGET_OBJECT);
  2225.         worm[player].lives += ADD_SUPERHEALER;
  2226.         stat(player, MINIHEALER);
  2227.     break;
  2228.     case UMBRELLA:
  2229.         level += arand(1) + 1;
  2230.         if (level >= levels)
  2231.             level = levels;
  2232.         endoflevel();
  2233.     break;
  2234.     case AUTOJUMP:
  2235.         effect(FXGET_OBJECT);
  2236.         worm[player].autojump = TRUE;
  2237.         icon(player, AUTOJUMP);
  2238.     break;
  2239.     case SLOWER:
  2240.         effect(FXGET_OBJECT);
  2241.         for (i = 0; i <= CREATURES; i++)
  2242.         {   if
  2243.             (   creature[i].alive
  2244.              && creature[i].species != MISSILE_C
  2245.             )
  2246.             {   creature[i].speed = slowdown(creature[i].speed, FALSE, FALSE);
  2247.         }   }
  2248.     break;
  2249.     case PULSE:
  2250.         effect(FXBORN_FRAGMENT);
  2251.         for (i = 0; i <= CREATURES; i++)
  2252.         {   if (!creature[i].alive && generated <= 7)
  2253.             {   switch (generated)
  2254.                 {
  2255.                 case 0:
  2256.                     xx = 0;
  2257.                     yy = -1;
  2258.                 break;
  2259.                 case 1:
  2260.                     xx = 1;
  2261.                     yy = -1;
  2262.                 break;
  2263.                 case 2:
  2264.                     xx = 1;
  2265.                     yy = 0;
  2266.                 break;
  2267.                 case 3:
  2268.                     xx = 1;
  2269.                     yy = 1;
  2270.                 break;
  2271.                 case 4:
  2272.                     xx = 0;
  2273.                     yy = 1;
  2274.                 break;
  2275.                 case 5:
  2276.                     xx = -1;
  2277.                     yy = 1;
  2278.                 break;
  2279.                 case 6:
  2280.                     xx = -1;
  2281.                     yy = 0;
  2282.                 break;
  2283.                 case 7:
  2284.                     xx = -1;
  2285.                     yy = -1;
  2286.                 break;
  2287.                 default:
  2288.                     // assert(0);
  2289.                     xx = yy = 0; // to avoid spurious warnings
  2290.                 break;
  2291.                 }
  2292.  
  2293.                 generated++;
  2294.                 if (valid(x + xx, y + yy) && (xx != worm[player].deltax || yy != worm[player].deltay))
  2295.                 {   d = field[x + xx][y + yy];
  2296.                     if
  2297.                     (   (d >= FIRSTEMPTY && d <= LASTEMPTY)
  2298.                      || (d >= FIRSTTAIL  && d <= LASTTAIL )
  2299.                      || d <= LASTOBJECT
  2300.                     )
  2301.                     {   createcreature(FRAGMENT, i, x + xx, y + yy, xx, yy, 255, FRAGMENT);
  2302.         }   }   }   }
  2303.     break;
  2304.     case REMNANTS:
  2305.         effect(FXGET_OBJECT);
  2306.         worm[player].remnants = TRUE;
  2307.         icon(player, REMNANTS);
  2308.     break;
  2309.     case SIDESHOT:
  2310.         effect(FXGET_POWERUP);
  2311.         worm[player].sideshot = TRUE;
  2312.         icon(player, SIDESHOT);
  2313.     break;
  2314.     case MAGNET:
  2315.         effect(FXGET_OBJECT);
  2316.         i = 0;
  2317.         field[x][y] = EMPTY; // so that the magnet itself is destroyed
  2318.         for (xx = 0; xx <= fieldx; xx++)
  2319.             for (yy = 0; yy <= fieldy; yy++)
  2320.                 if (field[xx][yy] <= LASTOBJECT)
  2321.                 {   while (magnet[i].alive && i < MAGNETS)
  2322.                         i++;
  2323.                     if (i > MAGNETS)
  2324.                     {   break;
  2325.                     } else
  2326.                     {   magnet[i].x      = xx;
  2327.                         magnet[i].y      = yy;
  2328.                         magnet[i].object = field[xx][yy];
  2329.                         magnet[i].player = player;
  2330.                         magnet[i].alive  = TRUE;
  2331.                         i++;
  2332.                 }   }
  2333.     break;
  2334.     case CUTTER:
  2335.         effect(FXGET_OBJECT);
  2336.         worm[player].cutter += ADD_CUTTER + arand(RAND_CUTTER);
  2337.         if (worm[player].cutter > CUTTERLIMIT)
  2338.         {   worm[player].cutter = CUTTERLIMIT;
  2339.         }
  2340.         icon(player, CUTTER);
  2341.     break;
  2342.     case CYCLONE_O:
  2343.         /* create cyclone */
  2344.         do
  2345.         {   x = arand(fieldx - 10) + 5;
  2346.             y = arand(fieldy - 5) + 5;
  2347.             d = field[x][y];
  2348.         } while (d < FIRSTEMPTY || d > LASTEMPTY);
  2349.         for (i = 0; i <= CREATURES; i++)
  2350.         {   if (!creature[i].alive)
  2351.             {   createcreature(CYCLONE_C, i, x, y, 0, 0, 255, 0);
  2352.                 break;
  2353.         }   }
  2354.     break;
  2355.     case LIGHTNING:
  2356.         effect(FXGET_LIGHTNING);
  2357.         for (xx = 0; xx <= fieldx; xx++)
  2358.         {   for (yy = 0; yy <= fieldy; yy++)
  2359.             {   otherfield[xx][yy] = EMPTY;
  2360.         }   }
  2361.         for (xx = 0; xx <= fieldx; xx++)
  2362.         {   for (yy = 0; yy <= fieldy; yy++)
  2363.             {   if
  2364.                 (   field[xx][yy] == FIRSTTAIL + player
  2365.                  || field[xx][yy] == FIRSTGLOW + player
  2366.                 )
  2367.                 {   for (xxx = xx - 1; xxx <= xx + 1; xxx++)
  2368.                     {   for (yyy = yy - 1; yyy <= yy + 1; yyy++)
  2369.                         {   if (valid(xxx, yyy))
  2370.                             {   d = field[xxx][yyy];
  2371.                                 if
  2372.                                 (   (d >= FIRSTTAIL && d <= LASTTAIL && d != FIRSTTAIL + player)
  2373.                                  || (d >= FIRSTGLOW && d <= LASTGLOW && d != FIRSTGLOW + player)
  2374.                                  ||  d == EMPTY
  2375.                                  ||  d <= LASTOBJECT
  2376.                                  ||  d >= FIRSTCREATURE
  2377.                                 )
  2378.                                 {   otherfield[xxx][yyy] = TEMPLIGHTNING;
  2379.                                     if (anims)
  2380.                                     {   draw(xxx, yyy, LIGHTNING);
  2381.         }   }   }   }   }   }   }   }
  2382.         for (xx = 0; xx <= fieldx; xx++)
  2383.         {   for (yy = 0; yy <= fieldy; yy++)
  2384.             {   if (otherfield[xx][yy] == TEMPLIGHTNING)
  2385.                 {   d = field[xx][yy];
  2386.                     if (d >= FIRSTCREATURE)
  2387.                     {   i = whichcreature(xx, yy, d, 255);
  2388.                         if
  2389.                         (   d == BIRD
  2390.                          || d == DOG
  2391.                          || player != creature[i].player
  2392.                         )
  2393.                         {   wormkillcreature(player, i);
  2394.                             change(xx, yy, EMPTY);
  2395.                     }   }
  2396.                     else
  2397.                     {   change(xx, yy, EMPTY);
  2398.         }   }   }   }
  2399.     break;
  2400.     case PUSHER:
  2401.         effect(FXGET_OBJECT);
  2402.         worm[player].pusher = TRUE;
  2403.         icon(player, PUSHER);
  2404.     break;
  2405.     case GLOW:
  2406.         effect(FXGET_OBJECT);
  2407.         worm[player].glow += ADD_GLOW + arand(RAND_GLOW);
  2408.         if (worm[player].glow > GLOWLIMIT)
  2409.             worm[player].glow = GLOWLIMIT;
  2410.         icon(player, GLOW);
  2411.     break;
  2412.     case ENCLOSER:
  2413.         effect(FXGET_OBJECT);
  2414.         worm[player].encloser = TRUE;
  2415.         icon(player, ENCLOSER);
  2416.     break;
  2417.     case CONVERTER:
  2418.         effect(FXGET_OBJECT);
  2419.         for (i = 0; i <= CREATURES; i++)
  2420.         {   if
  2421.             (   creature[i].alive
  2422.              && creature[i].species == FRAGMENT
  2423.              && creature[i].subspecies != BANANA
  2424.             )
  2425.             {   xx = creature[i].x;
  2426.                 yy = creature[i].y;
  2427.                 creature[i].alive = FALSE;
  2428.                 change(xx, yy, EMPTY);
  2429.                 createcreature(MISSILE_C, i, xx, yy, 0, 0, player, 0);
  2430.         }   }
  2431.     break;
  2432.     default:
  2433.         // assert(0);
  2434.     break;
  2435.     }
  2436.     return(score);
  2437. }
  2438.  
  2439. AGLOBAL void wormcol(SBYTE player, SBYTE x, SBYTE y)
  2440. {   ABOOL flag;
  2441.     UBYTE c = field[x][y], d;
  2442.     SBYTE i, xx, yy;
  2443.  
  2444.     if (c == EMPTY)
  2445.     {   wormscore(player, POINTS_EMPTY);
  2446.     } elif (c >= FIRSTHEAD && c <= LASTHEAD)
  2447.     {   wormworm(x, y, player, c - FIRSTHEAD);
  2448.     } elif (c == FROGTONGUE)
  2449.     {   if (worm[player].armour == 0)
  2450.         {   worm[player].cause = FROG;
  2451.             worm[player].alive = FALSE;
  2452.     }   }
  2453.     elif (c == ARROWUP)
  2454.     {   worm[player].speed = speedup(worm[player].speed, TRUE);
  2455.         worm[player].last = ARROWUP;
  2456.         stat(player, BRAKES);
  2457.     } elif (c == ARROWDOWN)
  2458.     {   if (worm[player].speed < SLOW) // so that the worm cannot be involuntarily brought to a total stop
  2459.         {    worm[player].speed = slowdown(worm[player].speed, TRUE, worm[player].brakes);
  2460.         }
  2461.         worm[player].last = ARROWDOWN;
  2462.         stat(player, BRAKES);
  2463.     } elif (c == FROST)
  2464.     {   worm[player].frosted = TRUE;
  2465.         worm[player].last = FROST;
  2466.     } elif (c >= FIRSTPROTECTOR && c <= LASTPROTECTOR)
  2467.     {   protworm(x, y, c - FIRSTPROTECTOR, player);
  2468.     } elif (c == START)
  2469.     {   level++;
  2470.         if (level >= levels)
  2471.             level = levels;
  2472.         endoflevel();
  2473.     } elif
  2474.     (   c == STONE
  2475.      || c == METAL
  2476.      || c == WOOD
  2477.      || (c >= FIRSTCREATURE && creatureinfo[c - FIRSTCREATURE].wall)
  2478.      || (c >= FIRSTTAIL && c <= LASTTAIL)
  2479.      || (c >= FIRSTGLOW && c <= LASTGLOW)
  2480.     ) // if you've hit something that is pushable
  2481.     {   flag = TRUE; // flag is whether you deserve to be in pain
  2482.         if (worm[player].pusher)
  2483.         {   xx = x + worm[player].deltax;
  2484.             yy = y + worm[player].deltay;
  2485.             if (valid(xx, yy))
  2486.             {   d = field[xx][yy];
  2487.                 if
  2488.                 (    d <= LASTOBJECT
  2489.                  || (d >= FIRSTEMPTY && d <= LASTEMPTY)
  2490.                 )
  2491.                 // if pushing the square into a square which
  2492.                 // has an object or is empty/silver/gold
  2493.                 {   flag = FALSE; // then worm doesn't die
  2494.                     if (c >= FIRSTCREATURE)
  2495.                     {   // assert(creatureinfo[c - FIRSTCREATURE].wall);
  2496.                         i = whichcreature(x, y, c, 255);
  2497.                         creature[i].x = xx;
  2498.                         creature[i].y = yy;
  2499.                         drawcreature(i);
  2500.                     } elif (c >= FIRSTTAIL && c <= LASTTAIL)
  2501.                     {   field[xx][yy] = c;
  2502.                         drawtail(xx, yy, tailfield[x][y] + ((c - FIRSTTAIL) * SECONDMAGIC));
  2503.                     } elif (c >= FIRSTGLOW && c <= LASTGLOW)
  2504.                     {   field[xx][yy] = c;
  2505.                         drawtail(xx, yy, tailfield[x][y] + ((c - FIRSTGLOW) * SECONDMAGIC));
  2506.                     } else
  2507.                     {   change(xx, yy, c);
  2508.             }   }   }
  2509.             else // if pushing off the field edges
  2510.             {   flag = FALSE; // then worm doesn't die
  2511.                 if (c >= FIRSTCREATURE && creatureinfo[c - FIRSTCREATURE].wall)
  2512.                 {   // assert(c <= LASTCREATURE);
  2513.                     wormkillcreature(player, whichcreature(x, y, c, 255));
  2514.         }   }   }
  2515.         if (flag) // if not pushing successfully
  2516.         {   if
  2517.             (   (c >= FIRSTTAIL && c <= LASTTAIL)
  2518.              || (c >= FIRSTGLOW && c <= LASTGLOW)
  2519.             )
  2520.             {   if (worm[player].armour > 0)
  2521.                 {   if (players > 1)
  2522.                     {   if
  2523.                         (   (c >= FIRSTTAIL && c <= LASTTAIL && player == c - FIRSTTAIL)
  2524.                          || (c >= FIRSTGLOW && c <= LASTGLOW && player == c - FIRSTGLOW)
  2525.                         )
  2526.                         {   worm[player].last = SILVER;
  2527.                         } else
  2528.                         {   worm[player].last = GOLD;
  2529.                 }   }   }
  2530.                 elif (!enclosed)
  2531.                 {   if
  2532.                     (   (c >= FIRSTTAIL && c <= LASTTAIL)
  2533.                      ||  player != c - FIRSTGLOW
  2534.                     )
  2535.                     {   if (!checkautojump(player))
  2536.                         {   worm[player].cause = c;
  2537.                             worm[player].alive = FALSE;
  2538.                             if (c >= FIRSTGLOW && c <= LASTGLOW)
  2539.                             {   ramming(player);
  2540.             }   }   }   }   }
  2541.             elif (c >= FIRSTCREATURE)
  2542.             {   // assert(creatureinfo[c - FIRSTCREATURE].wall);
  2543.                 if (!checkautojump(player))
  2544.                 {   i = whichcreature(x, y, c, 255);
  2545.                     wormcreature(player, i);
  2546.             }   }
  2547.             else
  2548.             {   if (!checkautojump(player))
  2549.                 {   worm[player].cause = c;
  2550.                     worm[player].alive = FALSE;
  2551.                     ramming(player);
  2552.     }   }   }   }
  2553.     elif (c == SLIME)
  2554.     {   if (worm[player].armour == 0)
  2555.         {   worm[player].cause = c;
  2556.             worm[player].alive = FALSE;
  2557.     }   }
  2558.     elif (c >= FIRSTCREATURE)
  2559.     {   // assert(!creatureinfo[c - FIRSTCREATURE].wall);
  2560.         i = whichcreature(x, y, c, 255);
  2561.         wormcreature(player, i);
  2562.     } elif (c == TELEPORT)
  2563.     {   i = whichteleport(x, y);
  2564.         if (blockedtel(i, worm[player].deltax, worm[player].deltay))
  2565.         {   worm[player].cause = TELEPORT;
  2566.             worm[player].alive = FALSE;
  2567.             ramming(player);
  2568.         } else
  2569.         {   effect(FXUSE_TELEPORT);
  2570.             worm[player].x = xwrap(teleport[partner(i)].x + worm[player].deltax);
  2571.             worm[player].y = ywrap(teleport[partner(i)].y + worm[player].deltay);
  2572.     }   }
  2573.     elif (c >= FIRSTGLOW && c <= LASTGLOW)
  2574.     {   if (player != c - FIRSTGLOW)
  2575.         {   if (worm[player].armour == 0)
  2576.             {   worm[player].cause = GLOW;
  2577.                 worm[player].alive = FALSE;
  2578.             }
  2579.             ramming(player);
  2580.     }   }
  2581.     else bothcol(player, x, y);
  2582. }
  2583.  
  2584. AGLOBAL void drawhead(SBYTE player)
  2585. {   if (worm[player].alive)
  2586.     {   if (worm[player].glow == 0)
  2587.         {   realdrawhead(worm[player].x, worm[player].y, eachworm[player][0][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  2588.             worm[player].flashed = FALSE;
  2589.         } else
  2590.         {   if (worm[player].glow < 10)
  2591.             {   if (!worm[player].flashed)
  2592.                 {   realdrawhead(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  2593.                 } else draw(worm[player].x, worm[player].y, WHITENED);
  2594.                 worm[player].flashed = !worm[player].flashed;
  2595.             } else realdrawhead(worm[player].x, worm[player].y, eachworm[player][1][worm[player].deltax + 1 + (worm[player].deltay + 1) * 3]);
  2596.     }   }
  2597.     else draw(worm[player].x, worm[player].y, FIRSTPAIN + player);
  2598. }
  2599.  
  2600. AGLOBAL SBYTE whichteleport(SBYTE x, SBYTE y)
  2601. {   SBYTE which;
  2602.  
  2603.     for (which = 0; which <= 1; which++)
  2604.         if (teleports && teleport[which].x == x && teleport[which].y == y)
  2605.             return((SBYTE) which);
  2606.     return((SBYTE) -1); /* error code */
  2607. }
  2608.  
  2609. AGLOBAL void enginerundown(SBYTE player)
  2610. {   SBYTE x, y;
  2611.     UBYTE i, j,
  2612.           multiply = worm[player].multi * players;
  2613.  
  2614.     quantity[0][0] = level - 1;
  2615.     quantity[0][1] = BONUS_LEVEL * multiply;
  2616.     quantity[0][2] = quantity[0][0] * quantity[0][1];
  2617.  
  2618.     quantity[1][0] = worm[player].numbers;
  2619.     quantity[1][1] = BONUS_NUMBER * multiply;
  2620.     quantity[1][2] = quantity[1][0] * quantity[1][1];
  2621.  
  2622.     quantity[2][0] = secondsleft;
  2623.     quantity[2][1] = BONUS_TIME * multiply;
  2624.     quantity[2][2] = quantity[2][0] * quantity[2][1];
  2625.  
  2626.     quantity[3][0] = 0;
  2627.     for (x = 0; x <= fieldx; x++)
  2628.     {   for (y = 0; y <= fieldy; y++)
  2629.         {   if (field[x][y] == FIRSTTAIL + player)
  2630.             {   quantity[3][0]++;
  2631.     }   }   }
  2632.     quantity[3][1] = BONUS_TAIL * multiply;
  2633.     quantity[3][2] = quantity[3][0] * quantity[3][1];
  2634.  
  2635.     quantity[4][0] = 0;
  2636.     for (x = 0; x <= fieldx; x++)
  2637.     {   for (y = 0; y <= fieldy; y++)
  2638.         {   if (field[x][y] == FIRSTGLOW + player)
  2639.             {   quantity[4][0]++;
  2640.     }   }   }
  2641.     quantity[4][1] = BONUS_GLOW * multiply;
  2642.     quantity[4][2] = quantity[4][0] * quantity[4][1];
  2643.  
  2644.     clearscreen();
  2645.     for (i = 0; i <= 3; i++)
  2646.         if (worm[i].control != NONE)
  2647.             for (j = 0; j <= LASTOBJECT; j++)
  2648.                 stat(i, j);
  2649.  
  2650.     systemrundown(player, multiply); // control returns when it's time to continue
  2651.  
  2652.     clearkybd();
  2653.     effect(FXRIFF);
  2654.     for (i = 0; i <= 3; i++)
  2655.     {   if (worm[i].control != NONE && worm[i].control != AMIGA)
  2656.         {   anykey(FALSE);
  2657.             break;
  2658. }   }   }
  2659.  
  2660. void stat(SBYTE player, SBYTE line)
  2661. {   ABOOL print = TRUE;
  2662.     SBYTE i, theline;
  2663.  
  2664.     strcpy(stattext, "       "); /* 7 spaces */
  2665.     switch (line)
  2666.     {
  2667.     case BONUS:
  2668.         while (worm[player].score >= worm[player].nextlife)
  2669.         {   worm[player].lives++;
  2670.             worm[player].nextlife += LIFEMODULO;
  2671.             stat(player, MINIHEALER);
  2672.         };
  2673.         if (worm[player].multi > 1)
  2674.             whiteline();
  2675.         else colourline(player);
  2676.         stcl_d(stattext, worm[player].score);
  2677.         theline = 0;
  2678.         for (i = 0; i <= 6; i++)
  2679.             if (!stattext[i])
  2680.                 stattext[i] = ' ';
  2681.         // score can't reach 10 million
  2682.     break;
  2683.     case MINIHEALER:
  2684.         if (worm[player].lives > LIVESLIMIT)
  2685.             worm[player].lives = LIVESLIMIT;
  2686.         colourline(player);
  2687.         stci_d(stattext, worm[player].lives);
  2688.         for (i = 0; i <= 6; i++)
  2689.             if (!stattext[i])
  2690.                 stattext[i] = ' ';
  2691.         theline = 1;
  2692.     break;
  2693.     case BRAKES:
  2694.         if (worm[player].brakes)
  2695.             whiteline();
  2696.         else colourline(player);
  2697.         if (worm[player].speed == FAST)
  2698.             strcpy(stattext, "Fast   ");
  2699.         elif (worm[player].speed == NORMAL)
  2700.             strcpy(stattext, "Normal ");
  2701.         elif (worm[player].speed == SLOW)
  2702.             strcpy(stattext, "Slow   ");
  2703.         else
  2704.         {   // assert(worm[player].brakes && worm[player].speed == 0);
  2705.             strcpy(stattext, "Stopped");
  2706.         }
  2707.         theline = 2;
  2708.     break;
  2709.     case AMMO:
  2710.         if (worm[player].ammo)
  2711.         {   if (worm[player].ammo > AMMOLIMIT)
  2712.                 worm[player].ammo = AMMOLIMIT;
  2713.             whiteline();
  2714.         } else colourline(player);
  2715.         stci_d(stattext, worm[player].ammo);
  2716.         for (i = 0; i <= 6; i++)
  2717.             if (!stattext[i])
  2718.                 stattext[i] = ' ';
  2719.         theline = 3;
  2720.     break;
  2721.     case POWER:
  2722.         switch(worm[player].power)
  2723.         {
  2724.         case 0:
  2725.             colourline(player);
  2726.             strcpy(stattext, "Single ");
  2727.         break;
  2728.         case 2:
  2729.             whiteline();
  2730.             strcpy(stattext, "Triple ");
  2731.         break;
  2732.         case 4:
  2733.             whiteline();
  2734.             strcpy(stattext, "Quint. ");
  2735.         break;
  2736.         case 6:
  2737.             whiteline();
  2738.             strcpy(stattext, "Sept.  ");
  2739.         break;
  2740.         default:
  2741.         break;
  2742.         }
  2743.         theline = 4;
  2744.     break;
  2745.     default:
  2746.         print = FALSE;
  2747.         /* This next line is just to prevent spurious compiler
  2748.         warnings about possibly uninitialized variables */
  2749.         theline = 0;
  2750.     break;
  2751.     }
  2752.  
  2753.     /* Sometimes stat() is called with a valid line, yet an invalid player.
  2754.     This is not a problem. */
  2755.  
  2756.     if (print)
  2757.     {   printstat(player, theline);
  2758. }   }
  2759.  
  2760. MODULE FLAG checkautojump(SBYTE player)
  2761. {   SBYTE distance, xx, yy;
  2762.  
  2763.     if (worm[player].autojump)
  2764.     {   if (worm[player].speed == FAST)
  2765.             distance = DISTANCE_FAST - 1;
  2766.         elif (worm[player].speed == NORMAL)
  2767.             distance = DISTANCE_NORMAL - 1;
  2768.         else
  2769.         {   // assert(worm[player].speed == SLOW);
  2770.             distance = DISTANCE_SLOW - 1;
  2771.         }
  2772.         xx = xwrap(worm[player].x + (worm[player].deltax * distance));
  2773.         yy = ywrap(worm[player].y + (worm[player].deltay * distance));
  2774.         if
  2775.         (   (field[xx][yy] >= FIRSTEMPTY && field[xx][yy] <= LASTEMPTY)
  2776.          || field[xx][yy] <= LASTOBJECT
  2777.         )
  2778.         {   worm[player].x = xx;
  2779.             worm[player].y = yy;
  2780.             wormcol(player, xx, yy);
  2781.             return(TRUE);
  2782.     }   }
  2783.     return(FALSE);
  2784. }
  2785.